hdu 3930 N次剩余

转载请注明出处,谢谢http://blog.csdn.net/bigtiao097?viewmode=contents

题意

给定newx, k, m, 方程 xknewx(mod m) , 求模m下x的所有解
0newx,m,k1.51015 m是素数。

思路

素数一定存在原根,首先求出m的原根g
根据原根的性质,一定存在 1ym1 使得 gynewx(mod m)
y可以通过大步小步算法来求,不会的可以看一下这道模板题
xkgy(mod m)
根据离散对数的性质可以得到

kloggxy(mod φ(m))

这里 φ(m) 是m的欧拉函数,由于m是素数, φ(m)=m1
对于上面这个方程,即
kloggxbφ(m)=y

即二元一次方程
axby=c

利用 扩展欧几里得算法可以求解


具体代码如下:
Result:Accepted     Memory: 12904K     Time : 46MS

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll g,y;
ll fac[20];//第i个因数
int cnt=0;//注意不要忘记初始化
int Case;
ll A,C,B;
ll mod_mul(ll x,ll n, ll mod)
{
    ll res = 0;
    while(n>0)
    {
        if(n&1) res = (res+x)%mod;
        x = (x<<1)%mod;
        n>>=1;
    }
    return res;
}
ll mod_pow(ll x,ll n, ll mod)
{
    x%=mod;
    ll res = 1;
    while(n>0)
    {
        if(n&1) res = mod_mul(res,x,mod);
        x = mod_mul(x,x,mod);
        n>>=1;
    }
    return res;
}
const int HASH_MOD=987654;
ll key[HASH_MOD], val[HASH_MOD];
int head[HASH_MOD], Next[HASH_MOD];
struct Hash{
    int tot;
    void init(){
        memset(head, -1, sizeof(head));
        tot = 0;
    }
    ll insert(ll x, ll y){
        int k = x % HASH_MOD;
        key[tot] = x;
        val[tot] = y;
        Next[tot] = head[k];
        head[k] = tot++;
    }
    ll find(ll x){
        int k = x % HASH_MOD;
        for(int i = head[k]; i != -1; i = Next[i])
            if(key[i] == x)
                return val[i];
        return -1;
    }
}hs;
ll log_mod(ll a, ll b, ll m){
    hs.init();
    ll s = ceil(sqrt(m + 0.5));
    ll cur = 1;
    for (int i = 0; i < s; ++i){
        if(hs.find(cur)==-1) hs.insert(cur,i);
        cur = cur * a % m;
    }

    ll v = mod_pow(a, (m - s - 1 + m) % m, m);
    for(int i = 0; i < s; ++i){
        ll tmp = hs.find(b);
        if(tmp!=-1)
            return s * i + tmp;
        b=b*v%m;
    }
    return -1;
}

vector<ll> a;
bool g_test(ll g,ll p){
    for(ll i=0;i<a.size();++i)
        if(mod_pow(g,(p-1)/a[i],p)==1)
            return 0;
    return 1;
}
ll priroot(ll p)
{
    a.clear();
    ll tmp=p-1;
    for(ll i=2;i<=tmp/i;++i)
        if(tmp%i==0){
            a.push_back(i);
            while(tmp%i==0)
                tmp/=i;
        }
    if(tmp!=1)
        a.push_back(tmp);
    ll g=1;
    while(true){
        if(g_test(g,p))
            return g;
        ++g;
    }
}
void  exgcd(ll a, ll b, ll& d, ll& x, ll& y)
{
    if(!b){ d = a; x = 1; y = 0;}
    else{ exgcd(b, a%b, d, y, x); y -= a/b*x; }
}
ll d;
vector<ll> solve(ll a, ll b,ll c)
{
    vector<ll> vec;
    ll x,y;
    exgcd(a, b, d, x, y);
    if(!d || c%d)
        return vec;
    x *= c/d;
    y *= c/d;
    a /= d;
    b /= d;
    if(a<0) a=-a;
    if(b<0) b=-b;
    ((x %= b) += b) %=b;//此时x+mb,y-ma都是解,m为自然数
    ((y %= a) += a) %=a;
    for(int i=0;i<d;i++)
        vec.push_back(mod_pow(g,x+i*b,C));
    sort(vec.begin(),vec.end());
    vec.erase(unique(vec.begin(),vec.end()),vec.end());
    return vec;

}
int main()
{
    vector<ll> vec;
    while(~scanf("%lld%lld%lld",&A,&C,&B))
    {
        printf("case%d:\n",++Case);
        g = priroot(C);
        y = log_mod(g,B,C);
        vec = solve(A,C-1,y);
        if(vec.size()==0)puts("-1");
        for(int i=0;i<vec.size();i++)
            printf("%lld\n",vec[i]);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值