• 数论之广义斐波那契循环节


    广义斐波那契:,满足,求

    acdreamers大佬的推导证明:广义Fibonacci数列找循环节

    首先我们肯定知道,这是可以写成矩阵快速幂的形式,问题就在于,n很大的时候呢?

    这就是有一个降幂公式,对于要模的数x,循环节就是,∏(pi-1)(pi+1) *x/∏pi

    也就是把x的所有质因子pi,把(pi-1)*(pi+1)全乘起来,然后乘上x/pi

    至于为什么,这个就不知道了。这个是由txdywjy灵机一闪,猜测出来的积性函数。

    直接作为模板用上了。

     所以牛客多校第5场的B可以直接降幂做,https://ac.nowcoder.com/acm/contest/885/B

      1 #include<cstdio>
      2 #include<cstring>
      3 typedef long long ll;
      4 const int N=1000000+10;
      5 struct Node{
      6     int r,c;
      7     ll jz[3][3];
      8     Node(){
      9         memset(jz,0,sizeof(jz));
     10     }
     11 };
     12 ll x0,x1,a,b,n,md,mmd;
     13 char s[N];
     14 int pn,pri[100000+10];
     15 void init(){
     16     ll lim;
     17     for(int i=2;i<=100000;i++){
     18         if(!pri[i]) pri[pn++]=i;
     19         for(int j=0;j<pn;j++){
     20             lim=1ll*i*pri[j];
     21             if(lim>100000) break;
     22             pri[lim]=1;
     23             if(i%pri[j]==0) break; 
     24         }
     25     }
     26 }
     27 ll solve(ll x){
     28     ll ans1=1,ans2=1,xx=x;
     29     for(int i=0;i<pn;i++){
     30         if(1ll*pri[i]*pri[i]>x) break;
     31         if(x%pri[i]==0){
     32             ans1*=(pri[i]-1)*(pri[i]+1);
     33             ans2*=pri[i];
     34             while(x%pri[i]==0) x/=pri[i];
     35         }
     36     }
     37     if(x>1){
     38         ans1*=(x-1)*(x+1);
     39         ans2*=x;
     40     }
     41     return xx/ans2*ans1;
     42 }
     43 ll mul(ll x,ll y,ll z){
     44     x%=z;
     45     y%=z;
     46     ll ans=0;
     47     while(y){
     48         if(y&1){
     49             ans+=x;
     50             if(ans>=z) ans-=z;
     51         }
     52         x<<=1;
     53         if(x>=z) x-=z;
     54         y>>=1;
     55     }
     56     return ans;
     57 }
     58 Node Nmul(Node x,Node y,ll z){
     59     Node ans;
     60     ans.r=x.r;
     61     ans.c=y.c;
     62     for(int i=0;i<x.r;i++)
     63         for(int j=0;j<y.c;j++)
     64             for(int k=0;k<x.c;k++){
     65                 ans.jz[i][j]+=mul(x.jz[i][k],y.jz[k][j],z);
     66                 if(ans.jz[i][j]>=z) ans.jz[i][j]-=z;
     67             }
     68     return ans;
     69 }
     70 Node Npow(Node x,ll y,ll z){
     71     Node ans;
     72     ans.r=x.r;
     73     ans.c=x.c;
     74     for(int i=0;i<ans.c;i++) ans.jz[i][i]=1;
     75     while(y){
     76         if(y&1) ans=Nmul(ans,x,z);
     77         x=Nmul(x,x,z);
     78         y>>=1;
     79     }
     80     return ans;
     81 }
     82 int main(){
     83     init();
     84     while(~scanf("%lld%lld%lld%lld",&x0,&x1,&a,&b)){
     85         scanf("%s%lld",s,&md);
     86         mmd=solve(md);
     87         n=0;
     88         int lens=strlen(s);
     89         for(int i=0;i<lens;i++){
     90             n=mul(n,10,mmd)+s[i]-'0'; 
     91             if(n>=mmd) n-=mmd;
     92         }
     93         Node A,T;
     94         A.r=2;
     95         A.c=1;
     96         A.jz[0][0]=x1;
     97         A.jz[1][0]=x0;
     98         T.r=2;
     99         T.c=2;
    100         T.jz[0][0]=a;
    101         T.jz[0][1]=b;
    102         T.jz[1][0]=1;
    103         if(n>1){
    104             T=Npow(T,n-1,md);
    105             A=Nmul(T,A,md);
    106         }
    107         printf("%lld
    ",A.jz[0][0]);
    108     }
    109     return 0;
    110 }
    降幂板子

     但这题,n明确给出了,我们也可以用十进制的快速幂来处理指数来做。

     1 #include<cstdio>
     2 #include<cstring>
     3 typedef long long ll;
     4 const int N=1000000+10;
     5 struct Node{
     6     int r,c;
     7     ll jz[3][3];
     8     Node(){
     9         memset(jz,0,sizeof(jz));
    10     }
    11 };
    12 ll x0,x1,a,b,n,md;
    13 char s[N];
    14 Node Nmul(Node x,Node y,ll z){
    15     Node ans;
    16     ans.r=x.r;
    17     ans.c=y.c;
    18     for(int i=0;i<x.r;i++)
    19         for(int j=0;j<y.c;j++)
    20             for(int k=0;k<x.c;k++){
    21                 ans.jz[i][j]+=x.jz[i][k]*y.jz[k][j]%z;
    22                 if(ans.jz[i][j]>=z) ans.jz[i][j]-=z;
    23             }
    24     return ans;
    25 }
    26 Node Npow(Node x,ll y,ll z){
    27     Node ans;
    28     ans.r=x.r;
    29     ans.c=x.c;
    30     for(int i=0;i<ans.c;i++) ans.jz[i][i]=1;
    31     while(y){
    32         if(y&1) ans=Nmul(ans,x,z);
    33         x=Nmul(x,x,z);
    34         y>>=1;
    35     }
    36     return ans;
    37 }
    38 int main(){
    39     while(~scanf("%lld%lld%lld%lld",&x0,&x1,&a,&b)){
    40         scanf("%s%lld",s,&md);
    41         Node A,T,B;
    42         B.r=2;B.c=2;
    43         for(int i=0;i<B.c;i++) B.jz[i][i]=1;
    44         A.r=2;A.c=1;
    45         A.jz[0][0]=x1;
    46         A.jz[1][0]=x0;
    47         T.r=2;T.c=2;
    48         T.jz[0][0]=a;
    49         T.jz[0][1]=b;
    50         T.jz[1][0]=1;
    51         n=0;
    52         int lens=strlen(s);
    53         for(int i=lens-1;i>=0;i--){
    54             if((s[i]-'0')!=0) B=Nmul(B,Npow(T,s[i]-'0',md),md); 
    55             T=Npow(T,10,md);
    56         }
    57         A=Nmul(B,A,md);
    58         printf("%lld
    ",A.jz[1][0]);
    59     }
    60     return 0;
    61 }
    十进制快速幂

    不过运行时间上,降幂是更快的,然后举一题需要降幂的例子。

    Best Solver

    HDU - 5451 

    题意:已知,给你整数x,和一个素数M,求[y]%M

     对于这题,首先也是先写出矩阵快速幂的形式,这个很好写,就不多说了,

    然后这里的指数是很长的,要求的,不能拆成十进制,所以需要降幂,因为m是质数,循环节就是(m-1)*(m+1)

    最后还有个根号六要处理,引用别人的

    首先(5+2sqrt(6))^n + (5-2sqrt(6))^n 是一个整数,且(5-2sqrt(6))^n < 1

    所以 (5+2sqrt(6))^n + (5-2sqrt(6))^n = x + y sqrt(6) + x - ysqrt(6)

    所以算出 (5+2sqrt(6))^n的整数部分x,答案就是2*x-1

     1 #include<cstdio>
     2 #include<cstring>
     3 typedef long long ll;
     4 struct Node{
     5     int r,c;
     6     ll jz[3][3];
     7     Node(){
     8         memset(jz,0,sizeof(jz));
     9     }
    10 };
    11 Node Nmul(Node x,Node y,ll z){
    12     Node ans;
    13     ans.r=x.r;
    14     ans.c=y.c;
    15     for(int i=0;i<x.r;i++)
    16         for(int j=0;j<y.c;j++)
    17             for(int k=0;k<x.c;k++){
    18                 ans.jz[i][j]+=x.jz[i][k]*y.jz[k][j]%z;
    19                 if(ans.jz[i][j]>=z) ans.jz[i][j]-=z;
    20             }
    21     return ans;
    22 }
    23 Node Npow(Node x,ll y,ll z){
    24     Node ans;
    25     ans.r=x.r;
    26     ans.c=x.c;
    27     for(int i=0;i<ans.c;i++) ans.jz[i][i]=1;
    28     while(y){
    29         if(y&1) ans=Nmul(ans,x,z);
    30         x=Nmul(x,x,z);
    31         y>>=1;
    32     }
    33     return ans;
    34 }
    35 ll poww(ll x,ll y,ll z){
    36     ll ans=1;
    37     while(y){
    38         if(y&1) ans=ans*x%z;
    39         x=x*x%z;
    40         y>>=1; 
    41     }
    42     return ans;
    43 }
    44 int main(){
    45     int t=1,C,md;
    46     ll n,mmd;
    47     scanf("%d",&C);
    48     while(t<=C){
    49         scanf("%lld%d",&n,&md);
    50         mmd=1ll*md*md-1;
    51         Node A,T;
    52         A.r=2;A.c=1;
    53         A.jz[0][0]=5;
    54         A.jz[1][0]=2;
    55         T.r=2;T.c=2;
    56         T.jz[0][0]=5;
    57         T.jz[0][1]=12;
    58         T.jz[1][0]=2;
    59         T.jz[1][1]=5;
    60         n=(poww(2,n,mmd)+1)%mmd;
    61         if(n>1){
    62             T=Npow(T,n-1,md);
    63             A=Nmul(T,A,md);
    64         }
    65         printf("Case #%d: %lld
    ",t++,(2ll*A.jz[0][0]-1+md)%md);
    66     }
    67     return 0;
    68 }
    板子板子
  • 相关阅读:
    FTP(文件传输协议)工作原理
    Web测试和App测试有什么区别
    JMeter中文版用户手册
    shell常用命令
    RAID技术介绍和总结
    SQL Insert语句数据以以unicode码存储 解决存储数据出现乱码的问题
    IIS 允许无后缀文件访问的配置
    cocos2dx 背景用小尺寸图片滚动填充的方法
    (转)Windows7 64位系统搭建Cocos2d-x 2.2.1最新版以及Android交叉编译环境(详细教程) .
    大数据应用期末总评
  • 原文地址:https://www.cnblogs.com/LMCC1108/p/11286388.html
Copyright © 2020-2023  润新知