题意:给出n和m,f(n)是斐波那契额数列的第n项,要求计算ans=f(1)^m+f(2)^m+....f(n)^m。即斐波那契额数列前n项的m次幂和。
解法:这题好像有两种解法:一种是循环节+CRT,一种是通项公式,其实这题也可以直接exBM就能AC了。这里我学习的是循环节+CRT的解法https://blog.csdn.net/ftx456789/article/details/99684004。这位博主写得巨好了,我自己总结一下。
大家都知道朴素的斐波那契额数列模一个质数是有循环节的,且这个循环节也比较好找,我们这里猜想其实斐波那契额数列的m次幂和也是要循环节的,但是模数是1e9不是质数很烦。我们把1e9质因数分解
1000000000=29∗59=512∗1953125
而如果模数是512和1953125的话是有循环节的,分别是768和7812500,也就是说我们可以快速计算答案在模512下的解以及答案在模1953125下的解。那么我们可以考虑先求出这两个解分别是a1和a2。那么就要如下同余方程组。
ans≡a1 (mod 512)
ans≡a2 (mod 1953125)
那么最后我们用CRT求出这个ans就可以了。
#include<bits/stdc++.h> using namespace std; typedef long long LL; const LL l1=768; //循环节1 const LL l2=7812500; //循环节2 const int P=1e9; LL f[l2+10],sum[l2+10]; int n,mi; LL m[5],a[5]; LL power(LL x,LL p) { LL ret=1; for (;p;p>>=1) { if (p&1) ret=ret*x%P; x=x*x%P; } return ret; } LL exgcd(LL a,LL b,LL &x,LL &y) { if (b==0) { x=1; y=0; return a; } else { LL tmp=exgcd(b,a%b,y,x); y-=x*(a/b); return tmp; } } long long work() { LL lcm=m[1],X=a[1],t,x,y; for (int i=2;i<=2;i++) { LL b=(a[i]-X%m[i]+m[i])%m[i]; LL d=exgcd(lcm,m[i],x,y); //解这个方程出来t的特解x t=(b/d)*x if (b%d) return -1; t=(b/d)*x%m[i]; X=(X+t*lcm); //那么X(k)=X(k-1)+tm lcm=lcm*m[i]/d; X=(X%lcm+lcm)%lcm; } return X; } int main() { cin>>n>>mi; f[0]=0; f[1]=1; for (int i=2;i<=l2;i++) f[i]=(f[i-1]+f[i-2])%P; for (int i=1;i<=l2;i++) sum[i]=(sum[i-1]+power(f[i],mi))%P; m[1]=512; m[2]=1953125; a[1]=((n/l1)*sum[l1]+sum[n%l1])%P; a[2]=((n/l2)*sum[l2]+sum[n%l2])%P; cout<<work()<<endl; return 0; }
1000000000=29∗59=512∗1953125