题目描述
WYF手中有这样一条递推式
WYF并不是想让你帮他做出结果,事实上,给定一个n,他能够迅速算出Fn。WYF只是想单纯的考验一下读者们。
输入描述
仅一行,三个整数N,F1,P
输出描述
仅一行,表示Fn模P的余数。
样例输入
5 1 100
样例输出
41
注释
对20%的数据,N≤1000。
对50%的数据,N≤10000000。
对100%的数据,N、F1≤1018,P≤109
解题思路
N<=1e18,最后的复杂度应该是O(1)或者O(lg(N))
直接模拟式o(N^2)的,显然不行,虽然可以骗到20分。
考虑累加中每一项之前都乘了n^2,可以算一下f(n+1)-f(n)
F(n)=F(n-1)+(n-1)∑(k=1) (n-k)*F(k)(n>=3)
每一个f之前都乘了n,所以考虑再减一下
F(n)=2*F(n-1)-F(n-2)+(n-1)∑(k=1)F(k) (n>=4)
那如果再减一下,是不是就没有∑了,于是我又减了一下
F(n)=4*F(n-1)-3*F(n-2)+F(n-3) (n>=5)
看到这个样子就很舒服了,明显矩阵快速幂,但是我手残,总是忘记longlong越界之类的问题,调了一下午,终于过了。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 long long n,p,t; 6 struct mat 7 { 8 long long a[4][4]; 9 mat() 10 { 11 memset(a,0,sizeof(a)); 12 } 13 mat operator * (mat x) 14 { 15 mat ans; 16 for(int i=1;i<=3;i++) 17 for(int j=1;j<=3;j++) 18 for(int k=1;k<=3;k++) 19 ans.a[i][j]+=a[i][k]*x.a[k][j],ans.a[i][j]=(ans.a[i][j]+p)%p; 20 return ans; 21 } 22 }f,chg; 23 mat mul(mat x,long long k) 24 { 25 mat res; 26 res.a[1][1]=res.a[2][2]=res.a[3][3]=1; 27 for(long long i=k;i;i>>=1,x=x*x) 28 if(i&1) 29 res=res*x; 30 return res; 31 } 32 int main() 33 { 34 scanf("%lld%lld%lld",&n,&t,&p); 35 if(n==1||n==2) 36 printf("%lld ",t%p); 37 else if(n==3) 38 printf("%lld ",(4*t)%p); 39 else if(n==4) 40 printf("%lld ",(13*(t%p))%p); 41 else 42 { 43 f.a[1][1]=(13*(t%p))%p,f.a[1][2]=(4*t)%p,f.a[1][3]=t%p; 44 chg.a[1][1]=4,chg.a[1][2]=1,chg.a[1][3]=0,chg.a[2][1]=-3,chg.a[2][2]=0,chg.a[2][3]=1,chg.a[3][1]=1,chg.a[3][2]=0,chg.a[3][3]=0; 45 chg=mul(chg,n-4); 46 f=f*chg; 47 printf("%lld ",f.a[1][1]); 48 } 49 return 0; 50 }