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);
}
posted @ 2018-08-02 09:54  扩展的灰(Extended_Ash)  阅读(176)  评论(0编辑  收藏  举报