• 51Nod1038 X^A Mod P



    题目看这里
    经典的n次剩余问题,用到很多数论知识点
    1.扩展gcd
    2.原根
    3.离散对数
    4.n次剩余
    说一下这个算法的流程
    首先,我们的方程为xn=a(mod m) m为质数
    那么,我们首先要找m的原根g,这里g要满足的性 质就是对于i<j<m,gigj(mod m)
    那么,任何一个x<m都可以和一个gx对应,而且是唯一对应
    我们用离散对数求出一个t使得a=gt
    把原来的方程化为ny=t(mod m1)
    这个就可以用扩展gcd求解了
    还是比较简洁的,就是跑得很慢,主要是离散对数

    #pragma GCC optimize("O3")
    #pragma G++ optimize("O3")
    #include<math.h>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define LL long long 
    using namespace std;
    int w[50010],t=0; bool vis[100010];
    inline LL pow(LL x,LL k,LL M,LL s=1){
        for(;k;x=x*x%M,k>>=1) k&1?s=s*x%M:0;
        return s;
    }
    inline LL exgcd(LL a,LL b,LL& x,LL& y){
        if(b){
            LL r=exgcd(b,a%b,y,x);
            y-=x*(a/b); return r;
        } else { x=1; y=0; return a; }
    }
    inline void init(){
        for(int i=2;i<=100000;++i){
            if(!vis[i]) w[++t]=i;
            for(int j=1,k;(k=i*w[j])<=100000;++j){
                vis[k]=1;
                if(i%w[j]==0) break;
            }
        }
    }
    inline int gRt(LL p){
        LL s=p-1,r[40]={0},c=0;
        for(int i=1,j;w[i]*w[i]<=s;++i)
            if(s%(j=w[i])==0) for(r[++c]=j;s%j==0;s/=j);
        if(s>1) r[++c]=s;
        for(int g=1;;){
            begin:
            for(int i=1;i<=c;++i)
                if(pow(g,(p-1)/r[i],p)==1){ ++g; goto begin; }
            return g;
        }
    }
    struct P{
        LL x,y;
        inline bool operator< (const P& b){
            return x==b.x?y<b.y:x<b.x; 
        }
    } s[100010],a;
    inline LL log(LL x,LL n,LL m){
        LL q=sqrt(m)+1,c=1,inv,r;
        for(int i=0;i<q;++i){
            s[i]=(P){c,i}; c=c*x%m;
        }
        sort(s,s+q); inv=pow(c,m-2,m); c=1;
        for(int i=0;i<q;++i){
            r=n*c%m;
            a=*lower_bound(s,s+q,(P){r,-1});
            if(a.x==r) return i*q+a.y;
            c=c*inv%m;
        }
        return -1;
    }
    int W[100000];
    inline int Ndx(int M,int n,int a){
        if(!a) return puts("0");
        int g=gRt(M); LL m=log(g,a,M);
        if(m<0) return puts("No Solution");
        LL x,y,r=exgcd(n,--M,x,y),d;
        if(m%r) return puts("No Solution");
        x=x*(m/r)%M; d=M/r;
        for(int i=0;i<r;++i){
            x=(x+d+M)%M;
            W[i]=pow(g,x,M+1);
        }
        sort(W,W+r);
        for(int i=0;i<r;++i) printf("%d ",W[i]); puts("");
    }
    int main(){
        int T,N,M,A; init();
        for(scanf("%d",&T);T--;Ndx(M,N,A)) scanf("%d%d%d",&M,&N,&A);
    }
  • 相关阅读:
    Windows下利用TortoiseSVN搭建本地SVN服务器
    我的Netty笔记
    Netty简单的HTTP服务器
    开启和关闭HBase的thrift进程
    java中重载和重写的区别
    java中形参个数可变的方法使用
    java中方法的参数传递机制
    Java内存分配全面浅析
    java中的类修饰符、成员变量修饰符、方法修饰符。
    js实现页面重定向
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477069.html
Copyright © 2020-2023  润新知