http://www.lydsy.com/JudgeOnline/problem.php?id=2326 http://codevs.cn/problem/2314/
题意:求123456789101112……n对m取模的结果。n<=10^18,m<=10^9。
记f(i)=Concatenate(1...i),则有f(i+1)=f(i)*10^k+i+1,其中k为i+1的位数。
首先,对于连续的一段递推式,10^k的值是不变的,因此可以考虑分段进行矩阵乘法快速幂来优化递推。
但是这里下标i的值也参与了计算,因此我们可以考虑维护一个值使其总是等于下标,于是我们有:
[ f(i), i, 1 ] * [ base, 0, 0 ] = [ f(i+1), i+1, 1 ]
[ 1, 1, 0 ]
[ 1, 1, 1 ]
或
[ f(i), i+1, 1 ] * [ base, 0, 0 ] = [ f(i+1), i+2, 1 ]
[ 1, 1, 0 ]
[ 0, 1, 1 ]
我写的是后者。
代码:
#include<cstdio>
#include<cstring>
#define rpt(i,l,r) for(i=l;i<=r;i++)
long long n,k;
int m;
struct matrix{
int v[3][3];
void print(){
int i,j;
rpt(i,0,2){
rpt(j,0,2) printf("%d ",v[i][j]);
printf("\n");
}
}
}a,b,c;
matrix operator *(matrix a,matrix b){
matrix res;
int i,j,k;
memset(res.v,0,sizeof(res.v));
rpt(i,0,2) rpt(j,0,2) rpt(k,0,2)
(res.v[i][j]+= (int)((long long)a.v[i][k]*b.v[k][j]%m) )%=m;
return res;
}
const matrix I=(matrix){1,0,0,0,1,0,0,0,1};
matrix operator ^(matrix a,long long x){
matrix res=I;
while(x){
if(x&1) res=res*a;
x>>=1;a=a*a;
}
return res;
}
int main(){
scanf("%lld%d",&n,&m);
a=(matrix){0,1,1,0,0,0,0,0,0};
b=(matrix){10,0,0,1,1,0,0,1,1};
k=1;
while(k<=n/10){
a=a*(b^(k*10-k));
k*=10;
b.v[0][0]=(int)(k*10%m);
}
a=a*(b^(n-k+1));
printf("%d",a.v[0][0]);
}