zoukankan      html  css  js  c++  java
  • bzoj 1409 Password 矩阵快速幂+欧拉函数

    可以发现,该数组的mi就是斐波那契数列
    所以要矩阵快速幂搞出第n位
    但是斐波那契数列上涨的很快,这就需要欧拉定理了
    p^phi(q)%q=1(gcd(p,q)==1)
    p是素数,所以可以用
    然后需要5000个数的phi,q<=2^31
    筛出sqrt(2^31)范围内的素数,然后直接找单个数的欧拉函数就好了

    最后再套个快速幂就A了

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    int m,n,p,q,prime[80005],tot;
    bool bo[80050];
    long long a[3][3],b[3][3],c[3][3];
    void getprime(int N=80005){
        for(int i=2;i<=N;i++){
            if(!bo[i])prime[++tot]=i;
            for(int j=1;j<=tot&&i*prime[j]<=N;j++){
                bo[i*prime[j]]=1;
                if(!i%prime[j]) break;
            }
        }
    }
    void poww(long long A[3][3],long long B[3][3],long long C[3][3],int pp){
        long long D[3][3]={0};
        for(int j=1;j<=2;j++){
            for(int i=1;i<=2;i++){
                D[i][j]=0;
                for(int k=1;k<=2;k++){
                    D[i][j]+=A[i][k]*B[k][j];
                    D[i][j]%=pp;
                }
            }
        }
        for(int j=1;j<=2;j++)
            for(int i=1;i<=2;i++)
                C[i][j]=D[i][j];
    }
    int getphi(int x){
        int xx=x;
        for(int i=1;prime[i]*prime[i]<=xx;i++){
            if(!(xx%prime[i])){
                x/=prime[i];x*=(prime[i]-1);
                while(!(xx%prime[i]))xx/=prime[i];
            }
        }
        if(xx!=1){x/=xx;x*=(xx-1);}
        return x;
    }
    int main()
    {
        scanf("%d%d",&m,&p);
        getprime();
        for(int i=1;i<=m;i++){
            //printf("i==%d
    ",i);
            scanf("%d%d",&n,&q);
            a[1][1]=a[1][2]=a[2][1]=1; a[2][2]=0;
            b[1][1]=b[1][2]=1;
            c[1][1]=c[2][2]=1; c[1][2]=c[2][1]=0;
            int qq=getphi(q);
            //printf("q==%d  qq==%d
    ",q,qq);
            if(n<=2){
                printf("%d
    ",p%q);
                continue;
            }
            n-=2;
            while(n){
                if(n&1) poww(c,a,c,qq);
                poww(a,a,a,qq);
                n>>=1;
            }
            poww(b,c,b,qq);
            int mi=b[1][1]; 
            //printf("mi==%d
    ",mi);
            long long pp=p,ans=1;
            while(mi){
                if(mi&1) ans=(ans*pp)%q;
                pp=(pp*pp)%q;
                mi>>=1;
            }
            printf("%lld
    ",ans%q);
        }
        return 0;
    }


  • 相关阅读:
    一步一步写数据结构(线索二叉树)
    Android studio 下JNI编程实例并生成so库
    IOS和Android音频开发总结
    IDEA常用快捷键
    Spring事务简介
    IDEA新建Springboot项目
    140201126杨鹏飞作业六
    140201126杨鹏飞作业三
    140201126杨鹏飞作业七
    自我介绍
  • 原文地址:https://www.cnblogs.com/Ren-Ivan/p/7746728.html
Copyright © 2011-2022 走看看