2019牛客暑期多校训练营(第九场)A:Power of Fibonacci(斐波拉契幂次和)
题意:求Σfi^m%p。 zoj上p是1e9+7,牛客是1e9; 对于这两个,分别有不同的做法。
前者利用公式,公式里面有sqrt(5),我们只需要二次剩余求即可。 后者mod=1e9,5才mod下没有二次剩余,所以不能这么做了。可以分解mod,然后利用循环节搞。
zoj:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N = 100005; const LL MOD = 1000000009; LL fac[N],A[N],B[N]; void Init() { fac[0] = 1; for(int i=1; i<N; i++) fac[i] = fac[i-1] * i % MOD; A[0] = B[0] = 1; for(int i=1; i<N; i++) { A[i] = A[i-1] * 691504013 % MOD; B[i] = B[i-1] * 308495997 % MOD; } } LL quick_mod(LL a,LL b,LL MOD) { LL ans = 1; a %= MOD; while(b){ if(b&1){ ans = ans * a % MOD; b--; } b>>=1; a = a * a % MOD; } return ans; } LL Solve(LL n,LL k) { LL ans = 0; for(int r=0; r<=k; r++) { LL t = A[k-r] * B[r] % MOD; LL x = fac[k]; LL y = fac[k-r] * fac[r] % MOD; LL c = x * quick_mod(y,MOD-2,MOD) % MOD; LL tmp = t * (quick_mod(t,n,MOD) - 1) % MOD * quick_mod(t-1,MOD-2,MOD) % MOD; if(t == 1) tmp = n % MOD; tmp = tmp * c % MOD; if(r & 1) ans -= tmp; else ans += tmp; ans %= MOD; } LL m = quick_mod(383008016,MOD-2,MOD); ans = ans * quick_mod(m,k,MOD) % MOD; ans = (ans % MOD + MOD) % MOD; return ans; } int main() { int T; LL n,k; Init(); scanf("%d",&T); while(T--) { cin>>n>>k; cout<<Solve(n,k)<<endl; } return 0; }
牛客: 你可以不熟悉斐波拉契的循环节具体怎么求,但是只要知道mod=p^a,fib[]%mod的循环节小于p^(a-1)* (2*p+2)。
而1e9计较特殊,1e9=2^9*5^9,这两部分对应的循环节都不是很大,所以我们可以分别求,然后中国剩余定理合并啊,就可以水过去了。
(但是我的代码怎么这么慢啊
#include<bits/stdc++.h> #define ll long long #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int Mod=1e9; int md[2]={512,1953125}; int f[8000000],ans[2]; int qpow(int a,int x,int p) { int res=1; while(x){ if(x&1) res=1LL*res*a%p; x>>=1; a=1LL*a*a%p; } return res; } void exgcd(int a,int b,int &x,int &y) { if(b==0){ x=1; y=0; return;} exgcd(b,a%b,y,x); y-=a/b*x; } int rev(int a,int b) { int x,y; exgcd(a,b,x,y); x=(x%b+b)%b; return x; } int main() { int N,M; scanf("%d%d",&N,&M); rep(k,0,1) { f[0]=0; f[1]=1; int j=2; for(;;j++){ f[j]=(f[j-1]+f[j-2]); if(f[j]>=md[k]) f[j]-=md[k]; if(f[j]==1&&f[j-1]==0) { j--; break; } } int P=N/j; for(int i=0;i<j;i++) { int t=qpow(f[i],M,md[k]); ans[k]=(ans[k]+1LL*t*(P+(i<=N%j)))%md[k]; } } int res=(1LL*ans[0]*md[1]%Mod*rev(md[1],md[0])%Mod+1LL*ans[1]*md[0]%Mod*rev(md[0],md[1])%Mod)%Mod; printf("%d\n",res); return 0; }
It is your time to fight!