题目描述 Description
小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题: 给定正整数 N 和 M ,要求计算 Concatenate (1 .. N ) Mod M 的值,其中Concatenate (1 .. N ) 是将所有正整数 1, 2, …, N 顺序连接起来得到的数。例如, N = 13, Concatenate (1 .. N ) = 12345678910111213. 小 C 想了大半天终于意识到这是一道不可能手算出来的题目,于是他只好向你求助,希望 你能编写一个程序帮他解决这个问题。
输入描述 Input Description
只有一行 为用空格隔开的两个正整数 N 和 M
输出描述 Output Description
仅包含一个非负整数,表示 Concatenate (1 .. N ) Mod M 的值
样例输入 Sample Input
13 13
样例输出 Sample Output
4
数据范围及提示 Data Size & Hint
其中 30%的数据满足1≤ N ≤1000000;100%的数据满足1≤ N ≤1018且1≤ M ≤109
/* 矩阵乘法 按位进行计算,公式很好推。 矩阵乘法写得少,导致代码特别难看。 */ #include<cstdio> #include<iostream> #define lon long long using namespace std; lon A[4][4],B[4][4],n,mod,ans; void mul(lon a[4][4],lon b[4][4],lon c[4][4]){ lon tmp[4][4]={0}; for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) for(int k=1;k<=3;k++) tmp[i][j]+=(a[i][k]*b[k][j])%mod,tmp[i][j]%=mod; for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) c[i][j]=tmp[i][j]; } void mi(lon a[4][4],lon b){ lon base[4][4]={0},r[4][4]={0}; for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) base[i][j]=a[i][j]; for(int i=1;i<=3;i++) r[i][i]=1; while(b){ if(b&1) mul(base,r,r); mul(base,base,base); b>>=1; } for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) a[i][j]=r[i][j]; } lon pow10(int x){ lon ans=1; for(int i=1;i<=x;i++) ans*=10; return ans; } void init(){ int ans=0; for(int i=1;i<=n;i++) ans=ans*10+i,ans%=mod; cout<<ans; } int main(){ cin>>n>>mod; if(n<10) {init();return 0;} ans=123456789; for(int i=2;i<=18;i++){ A[1][1]=ans;A[1][2]=pow10(i-1)%mod;A[1][3]=1; A[2][1]=A[2][2]=A[2][3]=0; A[3][1]=A[3][2]=A[3][3]=0; B[1][1]=pow10(i)%mod;B[1][2]=0;B[1][3]=0; B[2][1]=1;B[2][2]=1;B[2][3]=0; B[3][1]=0;B[3][2]=1;B[3][3]=1; lon ci=min(pow10(i)-1,n)-pow10(i-1)+1; if(ci<0) break; mi(B,ci); mul(A,B,A); ans=A[1][1]%mod; } cout<<ans; return 0; }