[BZOJ2326] [HNOI2011] 数学作业 (矩阵乘法)

时间:2023-03-09 07:54:15
[BZOJ2326] [HNOI2011] 数学作业 (矩阵乘法)

Description

[BZOJ2326] [HNOI2011] 数学作业 (矩阵乘法)

Input

Output

Sample Input

Sample Output

HINT

Source

Solution

  递推式长这样:$f[n]=f[n-1]*10^k+n$

  对于每一段位数个数相同的$n$(如$10\sim99,100\sim999,23333\sim66666,1018701389\sim2147483647$),$k$是个定值

  然后就可以开心地分段矩阵乘法了,剩下的自己推吧

 #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int mod;
struct mat
{
ll a[][];
int n, m; mat()
{
memset(a, , sizeof(a));
n = , m = ;
} mat(int x, int y)
{
memset(a, , sizeof(a));
n = x, m = y;
} mat operator* (const mat &rhs) const
{
mat ans;
ans.n = n, ans.m = rhs.m;
for(int i = ; i <= n; ++i)
for(int j = ; j <= rhs.m; ++j)
for(int k = ; k <= m; ++k)
ans.a[i][j] = (ans.a[i][j] + a[i][k] * rhs.a[k][j]) % mod;
return ans;
} mat operator^ (ll rhs) const
{
mat ans(n, n), b = *this;
for(int i = ; i <= n; ++i)
ans.a[i][i] = ;
for(; rhs; rhs >>= , b = b * b)
if(rhs & ) ans = ans * b;
return ans;
}
}; int main()
{
ll n, c;
mat ans(, ), b(, );
scanf("%lld%d", &n, &mod);
ans.a[][] = ;
for(int i = ; i <= ; ++i)
for(int j = ; j <= i; ++j)
b.a[i][j] = ;
for(ll i = ; ; i *= )
{
b.a[][] = i % mod;
if(i <= n) c = i / * ;
else c = n - i / + ;
ans = ans * (b ^ c);
if(i > n) break;
}
printf("%lld\n", ans.a[][]);
return ;
}