[HNOI2011] 数学作业
【题目描述】
solution:
用矩阵乘。
在向后插入数时,相当于把原答案乘10的多少次方再加上这个数,所以我们可以导成矩阵。
a矩阵 b矩阵
ans 10^j 1 0
i 0 1 1
1 0 0 1
b矩阵第一行是把ans*10^j+i,第二行是让i加1,第三行是保持a[3]=1.
由于10^j的j不同,所以我们应分层去求。
然后我们就可以开心地矩阵快速幂了。
注意时刻取模。
附上代码:
#include<iostream> #include<cstdlib> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; long long ans,a[10],b[10][10],n,mod; void ksc(long long); void hucheng(); void zicheng(); int main() { scanf("%lld%lld",&n,&mod); long long x=10,y=10,z=9; a[2]=1; a[3]=1; while(x<=n) { memset(b,0,sizeof(b)); b[1][1]=y; b[1][2]=b[2][2]=b[2][3]=b[3][3]=1; ksc(z); ans=a[1]; x*=10; y*=10; y%=mod; z*=10; } memset(b,0,sizeof(b)); b[1][1]=y; b[1][2]=b[2][2]=b[2][3]=b[3][3]=1; ksc(n-x/10+1); printf("%lld",a[1]); return 0; } void ksc(long long x) { while(x) { if((x&1)==1) hucheng(); x=x>>1; zicheng(); } } void hucheng() { long long c[7]; memset(c,0,sizeof(c)); for(long long i=1;i<=3;i++) for(long long j=1;j<=3;j++) { c[i]+=a[j]*b[i][j]; c[i]%=mod; } for(long long i=1;i<=3;i++) a[i]=c[i]; } void zicheng() { long long c[7][7]; memset(c,0,sizeof(c)); for(long long i=1;i<=3;i++) for(long long j=1;j<=3;j++) for(long long k=1;k<=3;k++) { c[i][j]+=b[i][k]*b[k][j]; c[i][j]%=mod; } for(long long i=1;i<=3;i++) for(long long j=1;j<=3;j++) b[i][j]=c[i][j]; }