bzoj2432: [Noi2011]兔農 快速冪+數論
阿新 • • 發佈:2019-02-14
不難發現,這個題就是求斐波那契數列改化,由於有一個很強的結論,斐波那契數列取模是一個週期數列,所以我們可以去找迴圈節,然後找到迴圈節後把這第一個迴圈節處理出來。 其實vfk說的很詳細了,注意這裡mod的數不一定是個質數,我們只能用拓展歐幾里得求逆元。。。。
http://vfleaking.blog.163.com/blog/static/174807634201341721051604/
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> using namespace std; #define oo 2000000000000000000000LL #define ll long long #define maxn 1000100 ll n,len[maxn],next[maxn]; int inv[maxn],k,mod; void init() { inv[1]=1; for(int i=2;i<k;i++) { inv[i]=(k-k/i)*inv[i]%k; } } ll gcd(ll &p,ll &q,ll x,ll y){ if(x==0){ p=1,q=1; return y; } ll r=gcd(q,p,y%x,x); p-=q*(y/x); return r; } ll gcd(ll x,ll y){ return x==0?y:gcd(y%x,x); } ll ni(ll x) { ll p,q; if(gcd(x,k)!=1)return 0; gcd(p,q,x,k); return (p%k+k)%k; } int pos[maxn],fib[maxn*6]; void firstap() { memset(pos,-1,sizeof(pos)); fib[0]=1;fib[1]=1;fib[2]=2; for(int i=3;!( fib[i-1]==1&& fib[i-2]==1);i++) { fib[i]=fib[i-1]+fib[i-2]; if(fib[i]>=k) fib[i]-=k; if(pos[fib[i]]==-1) pos[fib[i]]=i; } } struct matrix { int a[3][3]; void cl() { memset(a,0,sizeof(a)); } void one() { memset(a,0,sizeof(a)); for(int i=0;i<3;i++) a[i][i]=1; } void A() { a[0][0]=1;a[0][1]=1;a[0][2]=0; a[1][0]=1;a[1][1]=0;a[1][2]=0; a[2][0]=0;a[2][1]=0;a[2][2]=1; } void B() { a[0][0]=1;a[0][1]=1;a[0][2]=0; a[1][0]=1;a[1][1]=0;a[1][2]=0; a[2][0]=mod-1;a[2][1]=0;a[2][2]=1; } }; matrix operator *(matrix aa,matrix bb) { ll a[3][3]; for(int i=0;i<3;i++) for(int j=0;j<3;j++) { a[i][j]=0; for(int k=0;k<3;k++) { a[i][j]+=(ll)aa.a[i][k]*bb.a[k][j]%mod; a[i][j]%=mod; } } matrix cc; for(int i=0;i<3;i++) for(int j=0;j<3;j++) { cc.a[i][j]=a[i][j]; } return cc; } matrix matpow(matrix x,ll y) { matrix res;res.one(); while(y) { if(y&1){ res=res*x; } x=x*x; y>>=1; } return res; } int vis[maxn]; int main() { //freopen("rabbit20.in","r",stdin); scanf("%lld%d%d",&n,&k,&mod); for(int i=1;i<k;i++) inv[i]=ni(i); firstap(); for(int i=0;i<k;i++) { if(!inv[i]||!pos[inv[i]]) { next[i]=-1;len[i]=oo; } else { int kk=pos[inv[i]]; next[i]=(ll)fib[kk-1]*i%k; len[i]=kk+1; } } int cirs; for (cirs=1;cirs!=-1 && !vis[cirs];cirs=next[cirs]) vis[cirs]=1; matrix use; use.one(); matrix AA,BB; AA.A();BB.B(); for(int i=1;i!=cirs;i=next[i]) { if(n<len[i]) { use=use*matpow(AA,n); n=0; break; } else { use=use*matpow(AA,len[i]-1); use=use*BB; n-=len[i]; if(n==0) { break; } } } if(n>0) { int cur = cirs; ll totL = 0; matrix matC;matC.one(); do { matC = matC*matpow(AA,len[cur]-1); matC = matC*BB; totL += len[cur]; cur = next[cur]; } while (cur != cirs); use=use*matpow(matC, n / totL); n=n%totL; for(int i=cirs;;i=next[i]) { if(n<len[i]) { use=use*matpow(AA,n); break; } else { use=use*matpow(AA,len[i]-1); use=use*BB; n-=len[i]; if(n==0) { break; } } } } ll res=0; res=(ll)use.a[1][0]+(ll)use.a[2][0]; res= res%mod; cout << res << endl; return 0; }