zoukankan      html  css  js  c++  java
  • 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
    ",(ans.r[1][2]+Mod)%Mod);
    117 }
  • 相关阅读:
    eclipse 智能提示
    android 入门 004 (同一个方法,点击实现不同的效果)
    android 入门 003 (点击事件)
    android 入门 002 (拨打电话,发送短信)
    android 入门 001 (界面布局)
    Eclipse智能提示及快捷键
    转 Android学习笔记: 学习过程中碰到的一些问题及解决方法
    flash视频器播放器代码
    asp.net MVC webservice 报次错解决方法
    快递单号规则
  • 原文地址:https://www.cnblogs.com/qzqzgfy/p/5612072.html
Copyright © 2011-2022 走看看