codevs 2314 数学作业(矩阵乘法)
2314 数学作业
2011年省队选拔赛湖南
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 大师 Master
题目描述 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
/* 矩阵乘法 f[i]=f[i-1]*10的i的长度次方+i i的长度是不同的 没法直接矩阵乘法 按i的长度分情况用矩阵乘法 */ #include<iostream> #include<cstdio> #include<cstring> #define LL long long using namespace std; LL n,p; LL a[5][5],b[5][5],c[5][5],f[5][5]; LL init() { LL x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } LL slow_mul(LL a,LL b) { LL ret=0; while(b) { if(b&1)ret+=a,ret%=p,b--; a<<=1;a%=p;b>>=1; } return ret; } LL mul(LL a[5][5],LL b[5][5]) { for(LL i=1;i<=3;i++) { for(LL j=1;j<=3;j++) { LL x=0; for(LL k=1;k<=3;k++) x=(x+slow_mul(a[i][k],b[k][j]))%p; c[i][j]=x; } } for(LL i=1;i<=3;i++) { for(LL j=1;j<=3;j++) a[i][j]=c[i][j]; } } void pow(LL x) { if(x==1) { memcpy(a,b,sizeof(b)); return; } pow(x/2); mul(a,a); if(x&1)mul(a,b); } int main() { LL i,j,k; n=init();p=init(); f[1][2]=1;f[1][3]=1; b[2][1]=1;b[2][2]=1; b[3][2]=1;b[3][3]=1; for(i=10;i<=n;i*=10) { b[1][1]=i%p; pow(i-i/10); mul(f,a); } b[1][1]=i%p; pow(n-i/10+1); mul(f,a); cout<<f[1][1]<<endl; return 0; }