Description
小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题:给定正整数 N 和 M
要求计算 Concatenate (1 … N) Mod M 的值,其中 Concatenate (1 …N)是将所有正整数 1, 2, …, N 顺序连接起来得到的数。
例如,N = 13, Concatenate (1 … N)=12345678910111213.小C 想了大半天终于意识到这是一道不可能手算出来的题目,
于是他只好向你求助,希望你能编写一个程序帮他解决这个问题。
1≤N≤1018且1≤M≤109.
Solution
有一个十分显然的柿子是f[i]=f[i-1]*10^k+i,其中f[i]表示i的答案,k由i的位数决定
注意到当i的位数相同时k也是相同的,因此我们按照1~ 9,10~ 99,100~ 999这样的顺序做
f[i]的转移只和f[i-1]与i与1有关,矩阵加速即可
注意longlong变量模一个int变量的时候要考虑本来就比模数大的情况,没注意这个挂了40’QUQ
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
typedef unsigned long long LL;
int MOD;
struct Mat {
LL r[4][4];
Mat() {fill(r,0);}
Mat operator *(Mat B) const {
Mat A=*this,C;
rep(i,1,3) rep(j,1,3) {
rep(k,1,3) C.r[i][j]=(C.r[i][j]%MOD+A.r[i][k]*B.r[k][j]%MOD)%MOD;
}
return C;
}
Mat operator ^(LL dep) const {
Mat A=*this,C=*this; dep--;
for (;dep;dep>>=1) {
if (dep&1) C=C*A;
A=A*A;
}
return C;
}
} A,B;
int main(void) {
LL n; scanf("%llu%d",&n,&MOD);
LL ans=0,i=1;
while (i<=(long double)n/10.0) {
fill(A.r,0); A.r[1][1]=i*10LL%MOD;
A.r[2][1]=A.r[2][2]=A.r[3][1]=A.r[3][2]=A.r[3][3]=1;
A=A^(i*9);
ans=((ans%MOD)*(A.r[1][1]%MOD)%MOD+(A.r[2][1]%MOD)*((i-1)%MOD)%MOD+A.r[3][1])%MOD;
i=i*10LL;
}
fill(A.r,0); A.r[1][1]=i*10LL%MOD;
A.r[2][1]=A.r[2][2]=A.r[3][1]=A.r[3][2]=A.r[3][3]=1;
A=A^(n-i+1);
ans=((ans%MOD)*(A.r[1][1]%MOD)%MOD+(A.r[2][1]%MOD)*((i-1)%MOD)%MOD+A.r[3][1])%MOD;
printf("%llu\n", ans);
return 0;
/* ans=0;
rep(i,1,std:: min(9LL,n)) ans=(ans*10LL%MOD+i)%MOD;
rep(i,10,std:: min(99LL,n)) ans=(ans*100LL%MOD+i)%MOD;
rep(i,100,std:: min(999LL,n)) ans=(ans*1000LL%MOD+i)%MOD;
rep(i,1000,std:: min(9999LL,n)) ans=(ans*10000LL%MOD+i)%MOD;
rep(i,10000,std:: min(99999LL,n)) ans=(ans*100000LL%MOD+i)%MOD;
rep(i,100000,std:: min(999999LL,n)) ans=(ans*1000000LL%MOD+i)%MOD;
rep(i,1000000,std:: min(9999999LL,n)) ans=(ans*10000000LL%MOD+i)%MOD;
printf("%lld\n", ans);
*/}