题目描述
乐是做作业,给定正整数 N,M,要求计算Concatenate(1……N)mod M的值,其中Concatenate是指将1到N拼起来得到的数。如N=13,Concatenate=12345678910111213
输入格式
一行两个整数,N,M
输出格式
一个非负整数表示计算结果
样例输入
输出
数据范围
n ≤ 1 0 18 , m ≤ 1 0 9 n \leq 10^{18},m\leq 10^9 n ≤ 1 0 18 , m ≤ 1 0 9
分析
第一眼看到这题:暴力模拟
然后看到数据表示无语,1e18啊,这拼起来得多大
不管了先弄一个模拟:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <iostream> #include <cstdio> #include <cmath> using namespace std;unsigned long long s;int n, m;int wei (int x) { int s = 0 ; while (x) { s++; x /= 10 ; } return s; }int main () { freopen ("le.in" , "r" , stdin); freopen ("le.out" , "w" , stdout); cin >> n >> m; for (int i = 1 ; i <= n; i++) s = (s * pow (10 , wei (i)) + i), s = s % m; cout << s; return 0 ; }
这个应该很好懂,就不解释了,30分
作为一个合格的OI选手,一定是要考虑正解的。
设ans[i]表示拼接到i位时的答案,我们很容易得到递推式:
ans[i]=(ans[i-1]*p+i)%mod;
其中p表示当前i的位数乘十,先不考虑mod,比如ans[4]=123*10+4;
于是这又是一个递推式问题,那么怎么办呢?暴力跑一遍?1e18的数据不TLE算我输
所以这个时候矩阵快速幂来了……
可以设一个矩阵A为
{ans[i] i 1} 反正我是习惯开一维数组。。。。
然后另一个矩阵K为
{p 0 0}
{1 1 0}
{1 1 1}
这样A*K就能得到{ans[i]*p+i i+1 1}即{ans[i+1] i+1 1}
是不是很巧妙,所以不难看出上述A中的1的作用——与ans[i],凑出ans[i+1]和i+1.
接着考虑乘多少次方的问题,我们从i=0开始,如果n=4,那么显然要乘四次;
如果n=14呢?从0到9,一共要乘9次,然后再从10到14乘5次
接着多次进行迭代不难发现,我们可以用变量data拷贝n
如果n>=p就乘9*p/10次,data减去乘的值
当n < p 时说明不够乘了,所以直接乘以data次
最后跑快速幂就行了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <cstdio> #include <cstring> #include <algorithm> using namespace std;typedef unsigned long long ull; ull n,mod,a[4 ],c[4 ][4 ];void Mul () { ull cp[4 ]; memset (cp,0 ,sizeof (cp)); for (int i=1 ;i<=3 ;i++){ for (int j=1 ;j<=3 ;j++){ cp[i]+=((a[j]%mod)*(c[j][i]%mod))%mod; cp[i]%=mod; } } memcpy (a,cp,sizeof (cp)); }void Mulself () { ull cp[4 ][4 ]; memset (cp,0 ,sizeof (cp)); for (int i=1 ;i<=3 ;i++) for (int j=1 ;j<=3 ;j++) for (int k=1 ;k<=3 ;k++){ cp[i][j]+=((c[i][k]%mod)*(c[k][j]%mod))%mod; cp[i][j]%=mod; } memcpy (c,cp,sizeof (cp)); }int main () { scanf ("%llu%llu" ,&n,&mod); a[1 ]=0 ;a[2 ]=0 ;a[3 ]=1 ; ull mx=n*10 ,data=n; for (ull p=10LL ;p<=mx;p*=10LL ){ c[1 ][1 ]=p;c[1 ][2 ]=0 ;c[1 ][3 ]=0 ; c[2 ][1 ]=1 ;c[2 ][2 ]=1 ;c[2 ][3 ]=0 ; c[3 ][1 ]=1 ;c[3 ][2 ]=1 ;c[3 ][3 ]=1 ; ull x; if (n>=p){ x=9LL *p/10LL ; data-=x; } else x=data; while (x){ if (x&1 )Mul (); x>>=1 ; Mulself (); } } printf ("%llu\n" ,a[1 ]); }