654. A simple math problem
Time Limit: 1000 ms / Mem. Limit: 524288 KiB / IO: stdio
Given a number nnn, you should calculate 123456…11121314…n123456\ldots 11121314\ldots n123456…11121314…n module 11
Input
A single line with an integer nnn (0<n≤10180 < n \le 10^{18}0<n≤1018)
Output
Output one integer, 123456…11121314…n123456\ldots 11121314\ldots n123456…11121314…n module 11
Examples
Input 1
1
Output 1
1
Input 2
20
Output 2
5
Input 3
21
Output 3
4
Note
1≡1(mod11)1 \equiv 1 (\mod 11)1≡1(mod11)
1234567891011121314151617181920≡5(mod11)1234567891011121314151617181920 \equiv 5 (\mod 11)1234567891011121314151617181920≡5(mod11)
123456789101112131415161718192021≡4(mod11)123456789101112131415161718192021 \equiv 4 (\mod 11)123456789101112131415161718192021≡4(mod11).
Source
第六届华中区程序设计邀请赛暨武汉大学第十五届校赛
题目,很容易理解,输入一个n,把从1开始到n的所有数字连成一个数字,然后问这个数字模11的结果是什么。
首先,显然会想到n的结果就是n-1的结果乘上n的位数加上n再模11。O(n)的算法,但是仍然会超时。于是我就开始了漫长的找规律之旅,然后发现这是个无底洞……自己手残经常敲错东西,然后有时又忘了改一些东西。然后中午没有吃东西,脑子一片混乱,总之耗了一个多小时还没有弄出来。不,是WA了两次,然后放弃了。
现在想来,把我的思想总结一下就是f(n)=(f(n-1)*10^p+n)%11。其中p表示n的位数。我想,如果我把这个式子写出来或许我就可以想到矩阵快速幂了,然而……那么我们就来说说矩阵对递推的式的优化吧。对于任何线性的递推,我们都可以把递推关系写在矩阵里面,即可以把通项公式写成an=a0*matrix^n,这样子的话,我们就可以利用矩阵乘法优化这个递推的过程。
这题的话由于p的不同,所以我们要分成18个矩阵并分成一段一段地区求。构造方式的话设递推矩阵为x,x={{10^p,0,0}{1,1,0}{1,1,1}},然后的话首项是an={{an,n,1}{0,0,0}{0,0,0}},这样子刚好就可以完成递推,不信自己去试一试。关于构造这个矩阵,我记得我高中高OI的时候好像读过一篇文章专门讲如果构造递推矩阵,然而现在不记得了……下次找到了再讲吧。
还有,值得注意到是,对于求位数p,本想装个B用log换底直接求位数,但是由于一些精度问题老师错……最后还是妥协了……代码如下:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstdlib> #include<cmath> #include<cstring> #include<iomanip> #define ULL unsigned long long #define mod 11 #define N 4 using namespace std; struct matrix { ULL a[N][N]; } x,s,basic; ULL n,y; matrix matmulti(matrix x,matrix y) { matrix ans; for(int i=1;i<N;i++) for(int j=1;j<N;j++) { ans.a[i][j]=0; for(int k=1;k<N;k++) { ans.a[i][j]+=(x.a[i][k]*y.a[k][j])%mod; ans.a[i][j]%=mod; } } return ans; } matrix matpow(matrix x,ULL y) { if (y==0) return basic; else while ((y&1)==0) { y>>=1; x=matmulti(x,x); } matrix ans=x; y>>=1; while (y!=0) { x=matmulti(x,x); if ((y&1)!=0) ans=matmulti(ans,x); y>>=1; } return ans; } int main() { s.a[1][1]=0; x.a[2][1]=x.a[2][2]=1; s.a[1][2]=0;s.a[1][3]=1; x.a[3][1]=x.a[3][2]=x.a[3][3]=1; for(int i=1;i<=3;i++) basic.a[i][i]=1; scanf("%lld",&n); ULL nn=n,p=0; while (nn>0) { nn/=10; p++; } ULL i=10,j; for(i=10,j=1;j<p;i*=10,j++) { x.a[1][1]=i%mod; s=matmulti(s,matpow(x,9*i/10)); } x.a[1][1]=i%mod; s=matmulti(s,matpow(x,n-i/10+1)); printf("%lld",s.a[1][1]); }