51Nod1038 X^A Mod P

105 篇文章 0 订阅
57 篇文章 0 订阅


题目看这里
经典的n次剩余问题,用到很多数论知识点
1.扩展gcd
2.原根
3.离散对数
4.n次剩余
说一下这个算法的流程
首先,我们的方程为 xn=a(mod m) x n = a ( m o d   m ) m为质数
那么,我们首先要找m的原根g,这里g要满足的性 质就是对于 i<j<m,gigj(mod m) 任 意 i < j < m , g i ≠ g j ( m o d   m )
那么,任何一个 x<m x < m 都可以和一个 gx g x 对应,而且是唯一对应
我们用离散对数求出一个t使得 a=gt a = g t
把原来的方程化为 ny=t(mod m1) n ∗ y = t ( m o d   m − 1 )
这个就可以用扩展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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#define geo_max(a,b) (((a) > (b)) ? (a) : (b)) #define geo_min(a,b) (((a) < (b)) ? (a) : (b)) GEO_EXPORT mappoint geo_trangeo2map(georect* grt, geopoint* pt, maprect* mrt); GEO_EXPORT geopoint geo_tranmap2geo(maprect* mrt, mappoint* mpt, georect* grt); /* *判断点在不在矩形里.在返回0 * 不在返回-1 */ GEO_EXPORT int geo_gptingrt(geopoint* gpt, georect* grt); GEO_EXPORT int geo_mptinmrt(mappoint* mpt, maprect* mrt); GEO_EXPORT geobool geo_gptingpolygon(geopoint* gpt, geopoints *gpts); /* *返回单位为:米 */ GEO_EXPORT double geo_distance(geopoint* gptfrom, geopoint* gptto); GEO_EXPORT double geo_distance_pt2polyline(geopoint* gpt, geopoints* gpts, geopoint* rnearestpt); GEO_EXPORT double geo_distance_pt2polygon(geopoint* gpt, geopoints* gpts, geopoint* rnearestpt); /* *返回单位为:平方米 */ //GEO_EXPORT double geo_area(geopoints* gpts); /* *返回单位为:度 *正北为0度,顺时针为正 */ GEO_EXPORT double geo_direction(geopoint* gptfrom, geopoint* gptto); /* * 矩形与矩形的关系 * a 在 b 里面, 返回 0 * a 部份在 b 里面,返回 1 * a 没和 b 相交, 返回 -1 * /\ y * | * | * | * |------------> x * o */ int geo_grtingrt(georect* rta, georect* rtb); /* * 矩形与矩形的关系 * a 在 b 里面, 返回 0 * a 部份在 b 里面,返回 1 * a 没和 b 相交, 返回 -1 * * o * |------------> x * | * | * | * | * \/ y */ int geo_mrtinmrt(maprect* rta, maprect* rtb); //判断线段是否相关 //相交返回GEO_TRUE //不相交返回GEO_FALSE geobool geo_linecrossline(geopoint* lafrom, geopoint* lato, geopoint* lbfrom, geopoint* lbto); /* * 多边形与多边形的关系 * a 在 b 里面, 返回 0 * a 和 b 相交,返回 1 * a 没和 b 相交, 返回 -1 * b 在 a 里面, 返回 -2 * * /\ y * | * | * | * |------------> x * o */ int geo_gpolygoningpolygon(geopoints* gptsa, geopoints* gptsb);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值