【BZOJ2326】【HNOI2011】数学作业 [矩阵乘法][DP]
数学作业
Time Limit: 10 Sec Memory Limit: 128 MB[Submit][Status][Discuss]
Description
Input
输入文件只有一行为用空格隔开的两个正整数N和M。
Output
输出仅包含一个非负整数,表示Concatenate(1~N) MOD M的值。
Sample Input
12345678910 1000000000
Sample Output
345678910
HINT
1<=N<=10^8 , 1<=M<=10^9
Main idea
给定一个n,m,创造一个数字顺序连接1~n,输出这个数对m取模的值。
Solution
n<=10^18,排除找规律的可能性,立马想到了用矩阵乘法优化DP,令f[i]表示1~i的值,那么:
然后我们只要推出矩阵即可,轻松想到了:
然后分段矩乘得到答案。
Code
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstdio> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cmath> 8 using namespace std; 9 10 const int ONE=5; 11 12 long long n,MOD; 13 long long a[ONE][ONE],b[ONE][ONE]; 14 long long Index; 15 16 17 void Mul(long long a[ONE][ONE],long long b[ONE][ONE],long long ans[ONE][ONE]) 18 { 19 long long jilu[ONE][ONE]; 20 for(int i=1;i<=3;i++) 21 for(int j=1;j<=3;j++) 22 { 23 jilu[i][j]=0; 24 for(int k=1;k<=3;k++) 25 jilu[i][j]=(jilu[i][j] + a[i][k]*b[k][j]%MOD) % MOD; 26 } 27 28 for(int i=1;i<=3;i++) 29 for(int j=1;j<=3;j++) 30 ans[i][j]=jilu[i][j]; 31 } 32 33 void Matrix(long long a[ONE][ONE],long long b[ONE][ONE],long long t) 34 { 35 while(t) 36 { 37 if(t&1) Mul(a,b,a); 38 Mul(b,b,b); 39 t>>=1; 40 } 41 } 42 43 int main() 44 { 45 cin>>n>>MOD; 46 a[1][3]=1; 47 48 long long len=1; 49 for(;;) 50 { 51 len*=10; 52 memset(b,0,sizeof(b)); 53 for(int i=1;i<=3;i++) 54 { 55 for(int j=1;j<=i;j++) 56 b[i][j]=1; 57 } 58 b[1][1]=len % MOD; 59 60 if(len<=n) Index=len-len/10; 61 else Index=n-len/10+1; 62 Matrix(a,b,Index); 63 if(len>n) break; 64 } 65 66 printf("%lld",a[1][1]); 67 }