BZOJ 2432 兔农
http://www.lydsy.com/JudgeOnline/problem.php?id=2432
题意:f[1]=1 f[2]=1
x=f[i-1]+f[i-2] f[i]=x-1(x%K==1)|f[i]=x (x%K!=1)
求f[n]
参考:http://blog.csdn.net/u011265346/article/details/46331419
思路:首先,有个关键的东西:菲波那契数列在模下是有循环节的!
先构造一定的这些数列来观察一下:
1,1,2,3,5,0,
5,5,3,0,
3,3,6,2,0,
2,2,4,6,3,2,5,0,5,5,3,0,
3,3,6,2,0,
我们以0为分界线,对于每个部分:
每段开头两个其实都相等,都等于上一段的最后一个非0数字。
记斐波那契数列为fib[i],那么每段开头数字为s,每个数字就是fib[x]*s,x为这个数字在这段中位置。
记len为这段长度,那最后一个数字就是fib[len]*s,且fib[len]*s==1 %K
那我们为了找出循环节:
求x的逆元得到fib[len]
用fib[len]得到len
用x*fib[len-1]算出下一段段首,判断无循环或者继续做直到有循环节
具体实现:
1先记录fib的出现,然后就知道fib在模下的循环节了。
2然后对每个部分都记开头,直到找到循环节,就停止。
如果1中不存在逆元,或者2没有符合的len,那说明没有循环节,暴力算。
然后只要分类讨论就好了
做完我整个人都循环节了
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 #include<iostream> 6 #define ll long long 7 ll n,K,Mod; 8 bool don[1000005]; 9 ll len[1000005],vis[1000005],inv[1000005],f[6000005]; 10 struct Matrix{ 11 ll r[4][4]; 12 int n; 13 }ans,del,add,res[1000005]; 14 Matrix operator *(Matrix a,Matrix b){ 15 Matrix c; 16 c.n=a.n; 17 for (int i=0;i<=3;i++) 18 for (int j=0;j<=3;j++) 19 c.r[i][j]=0; 20 for (int i=0;i<=3;i++) 21 for (int j=0;j<=3;j++) 22 for (int k=0;k<=3;k++) 23 (c.r[i][j]+=(a.r[i][k]*b.r[k][j])%Mod)%=Mod; 24 return c; 25 } 26 Matrix operator ^(Matrix a,ll y){ 27 Matrix c; 28 for (int i=0;i<=3;i++) 29 for (int j=0;j<=3;j++) 30 c.r[i][j]=0; 31 for (int i=1;i<=3;i++) 32 c.r[i][i]=1; 33 while (y){ 34 if (y%2) c=c*a; 35 a=a*a; 36 y/=2; 37 } 38 return c; 39 } 40 void init(){ 41 f[1]=f[2]=1; 42 for (int i=3;;i++){ 43 f[i]=(f[i-1]+f[i-2])%K; 44 if (!vis[f[i]]) vis[f[i]]=i; 45 if (f[i]==1&&f[i-1]==1) break; 46 } 47 } 48 ll gcd(ll a,ll b){ 49 if (b==0) return a; 50 else return gcd(b,a%b); 51 } 52 void exgcd(ll a,ll b,ll &x,ll &y){ 53 if (b==0){ 54 x=1; 55 y=0; 56 return; 57 } 58 exgcd(b,a%b,x,y); 59 ll t=x; 60 x=y; 61 y=t-(a/b)*y; 62 } 63 ll ny(ll a){ 64 if (gcd(a,K)!=1) return -1; 65 ll x,y; 66 exgcd(a,K,x,y); 67 return (x+K)%K; 68 } 69 void solve(){ 70 for (int i=0;i<=3;i++) 71 for (int j=0;j<=3;j++) 72 del.r[i][j]=ans.r[i][j]=add.r[i][j]=0; 73 ans.r[1][1]=ans.r[1][3]=1; 74 bool flag=0; 75 ans.n=add.n=del.n=3; 76 add.r[1][2]=add.r[2][1]=add.r[2][2]=add.r[3][3]=1; 77 del.r[1][1]=del.r[2][2]=del.r[3][3]=1; 78 del.r[3][2]=-1; 79 for (ll t=1;n;){ 80 if (!inv[t]) {inv[t]=ny(t);} 81 if (inv[t]==-1){ans=ans*(add^n);n=0;} 82 else{ 83 if (!don[t]||flag){ 84 don[t]=1; 85 if (!vis[inv[t]]) {ans=ans*(add^n);n=0;} 86 else{ 87 len[t]=vis[inv[t]]; 88 if (n>=len[t]){ 89 n-=len[t]; 90 res[t]=(add^len[t])*del; 91 ans=ans*res[t]; 92 (t*=f[len[t]-1])%=K; 93 }else{ 94 ans=ans*(add^n); 95 n=0; 96 } 97 } 98 }else{ 99 ll cnt=0; 100 Matrix ret;ret.n=3;for (int i=0;i<=3;i++)for (int j=0;j<=3;j++) ret.r[i][j]=0; 101 ret.r[1][1]=ret.r[2][2]=ret.r[3][3]=1; 102 for (ll i=t*f[len[t]-1]%K;i!=t;(i*=f[len[i]-1])%=K){ 103 cnt+=len[i];ret=ret*res[i]; 104 } 105 cnt+=len[t];ret=res[t]*ret; 106 ans=ans*(ret^(n/cnt)); 107 n%=cnt;flag=1; 108 } 109 } 110 } 111 } 112 int main(){ 113 scanf("%lld%lld%lld",&n,&K,&Mod); 114 init(); 115 solve(); 116 printf("%lld\n",(ans.r[1][2]+Mod)%Mod); 117 }