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 }

 

posted @ 2016-06-23 20:47  GFY  阅读(307)  评论(0编辑  收藏  举报