[HNOI2011]数学作业 题解
这道题看着挺难然而其实看破了也挺容易的。首先N极其的大,几乎要炸掉long long ,所以O(n)的算法一定是扑街了,身为一个脑残志坚的OIer,怎能不想到矩阵快速幂优化呢?
有趣的是这道题矩阵有很多种,Q某犇有另一种做法,大家也可以去他那看一看。
答案矩阵是这样的:
f[x] x+1 1
被我们用来求答案的矩阵长这样:
10^t 0 0
1 1 0
0 1 1
其中t随我们现在处理的数的位数而改变。
然后这道题就硬生生的被我们搞成了一个矩阵快速幂的裸题。只要注意矩阵乘不满足交换律就是了。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<map> 7 #include<queue> 8 #include<string> 9 #include<cmath> 10 using namespace std; 11 long long n,m; 12 struct no{ 13 long long x,y; 14 long long a[20][20]; 15 no operator *(const no &c){ 16 no b; 17 memset(b.a,0,sizeof(b.a)); 18 b.x=x; 19 b.y=y; 20 for(int i=1;i<=x;i++) 21 { 22 for(int j=1;j<=y;j++) 23 { 24 for(int k=1;k<=y;k++) 25 { 26 b.a[i][j]+=((a[i][k]%m)*(c.a[k][j]%m))%m; 27 b.a[i][j]%=m; 28 } 29 } 30 } 31 return b; 32 } 33 }; 34 no ksm(long long x,no a,no b){ 35 no ans=a; 36 while(x) 37 { 38 if((x&1)) ans=ans*b; 39 b=b*b; 40 x>>=1; 41 } 42 return ans; 43 } 44 long long get(long long x){ 45 long long now=1; 46 no ans,a; 47 memset(a.a,0,sizeof(a.a)); 48 a.x=a.y=3; 49 a.a[2][1]=a.a[2][2]=a.a[3][2]=a.a[3][3]=1; 50 memset(ans.a,0,sizeof(ans.a)); 51 ans.x=1,ans.y=3; 52 ans.a[1][1]=0; 53 ans.a[1][2]=ans.a[1][3]=1; 54 for(int i=1;;i++) 55 { 56 now*=10; 57 if(x>(now-1)) 58 { 59 a.a[1][1]=now; 60 ans=ksm(now-now/10,ans,a); 61 } 62 else 63 { 64 a.a[1][1]=now; 65 ans=ksm(x-(now/10-1),ans,a); 66 break; 67 } 68 } 69 return ans.a[1][1]; 70 } 71 int main(){ 72 scanf("%lld%lld",&n,&m); 73 printf("%lld\n",get(n)); 74 //while(1); 75 return 0; 76 }