x^a=b(mod c)求解x在[0,c-1]上解的个数模板+原根求法

/*************************************
 求解x^a=b(mod c) x在[0,c-1]上解的个数模板
 输入:1e9>=a,b>=1,1e9>=c>=3.
 返回:调用xaeqbmodc(a,b,c),返回解的个数
 复杂度: 找原根的复杂度很低,所以总的复杂度为O(c^0.5)
 ************************************/

typedef long long ll;
#define HASH_N 100007

struct hashnode
{
    int next;
    ll key;
    int j;
}HashLink[ HASH_N ];

int hashpre[ HASH_N ],hashcnt;

void hash_insert(ll x,ll key,int j)
{
    for(int p=hashpre[x];p!=-1;p=HashLink[p].next)
    {
        if(HashLink[p].key==key) return ;
    }
    HashLink[ hashcnt ].key = key;
    HashLink[ hashcnt ].j = j;
    HashLink[ hashcnt ].next = hashpre[x];
    hashpre[x] = hashcnt++;
}

int hash_get(ll key)
{
    ll x=key%HASH_N;
    for(int p=hashpre[x];p!=-1;p=HashLink[p].next)
    {
        if( HashLink[p].key == key ) return HashLink[p].j;
    }
    return -1;
}

ll gcd(ll a,ll b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}

//ax + by = gcd(a,b)
//传入固定值a,b.放回 d=gcd(a,b), x , y
void extendgcd(long long a,long long b,long long &d,long long &x,long long &y)
{
    if(b==0){d=a;x=1;y=0;return;}
    extendgcd(b,a%b,d,y,x);
    y-=x*(a/b);
}

//Ax=1(mod M)
//返回x的范围是[0,M-1]
ll GetNi(ll A,ll M)
{
    ll rex=0,rey=0;
    ll td=0;
    extendgcd(A,M,td,rex,rey);
    return (rex%M+M)%M;
}

//a^b%mod 快速幂
long long Quk_Mul(long long a,long long b,long long mod)
{
    long long qsum=1;
    while(b)
    {
        if(b&1) qsum=(qsum*a)%mod;
        b>>=1;
        a=(a*a)%mod;
    }
    return qsum;
}

//测试x较小的情况,必须!
ll firsttest(ll A,ll B,ll C)
{
    ll tmp=1;
    if(B==1) return 0;
    for(int i=1;i<100;i++)
    {
        tmp = (tmp*A)%C;
        if(tmp==B) return i;
    }
    return -1;
}

ll BabyStep(ll A,ll B,ll C,ll OC)
{
    if(0==A || 0==C) return -1;
    if(C==1) return 0;
    B = B%C;
    ll ans = firsttest(A,B,C);//为了防止x比较小的时候
    if(ans != -1) return ans;
    ll D=1;
    int c=0;
    ll d;
    while( (d=gcd(A,C)) != 1 )
    {
        if( B%d !=0 ) return -1;//无解的情况
        B /= d;
        C /= d;
        D = D*A/d%C;
        c++;
    }

    //得到了 D*A^(x-c)=B (mod C) ,gcd(A,C)=1 , gcd(D,C)=1
    ll D_1=GetNi(D,C);//求D的逆元
    B = B*D_1%C;
    //求A^x=B (mod C),然后返回x+c
    ll m = ceil( sqrt(C+0.0) );

    memset(hashpre,-1,sizeof(hashpre));
    hashcnt=0;
    ll hashnum=1;
    hash_insert(1, 1, 0);
    for(int i=1;i<m;i++)
    {
        hashnum = (hashnum*A)%C;
        hash_insert(hashnum%HASH_N, hashnum ,i);
    }

    ll ol=OC;//这一步可以省略
    ll mA=Quk_Mul(A, m, C);
    ll ta=1;

    ll tmpni = Quk_Mul(mA, ol-1, C);

    for(int i=0;i<m;i++,ta=ta*tmpni%C)
    {
        //解线性同余方程 tx=B*ta (%C) ,ta直接用费马小定理求逆元
        ll tx = ta;
        tx = (tx*B)%C;
        int j=hash_get(tx);
        if(j!=-1)//找到解了
        {
            return i*m+j+c;
        }
    }

    return -1;
}

ll mypow(ll a,ll b)
{
    ll sum=1;
    for(int i=1;i<=b;i++)
        sum*=a;
    return sum;
}

ll slove(ll a,ll b,ll c,ll p,int a1)
{
    //第0种情况a==1
    if(a==1) return 1;

    //第一种情况b==c
    b %= c;
    if(b==0)
    {
        ll tmp = mypow(p,ceil( (double)a1/a ) );
        return c/tmp;
    }
    ll d=gcd(b,c);
    //第二种情况 gcd(b,c)!=1
    if( d != 1 )
    {
        return 0;
    }

    //第三种情况 gcd(b,c)==1

    //第一步找出原根x0,
    ll save[55];
    int cnt=0;

    ll tc = mypow(p,a1-1)*(p-1);
    for(ll i=2;i*i<=tc;i++)
    {
        if(tc%i == 0)
        {
            save[ cnt++ ] = i;
            while(tc%i==0) tc/=i;
        }
    }
    if(tc != 1)
    {
        save[ cnt++ ] = tc;
    }
    tc= mypow(p,a1-1)*(p-1);
    for(int i=0;i<cnt;i++)
    {
        save[i] = tc/save[i];
    }

    ll x0=0;
    for(int i=2;i<c;i++)
    {
        int flag=0;
        for(int j=0;j<cnt;j++)
        {
            if( Quk_Mul(i, save[j], c) ==1)
            {
                flag=1;
                break;
            }
        }
        if(flag==0)
        {
            x0=i;
            break;
        }
    }
    //找到原根x0后,然后找x0^a0 = b (mod c)
    ll a0 = BabyStep(x0 , b, c,mypow(p,a1-1)*(p-1));
    ll ord = mypow(p,a1-1)*(p-1);
    d = gcd(a,ord);
    if( a0%d != 0 ) return 0;
    return d;
}

ll xaeqbmodc(ll a,ll b,ll c)
{
    ll ans=1;
    b%=c;
    ll tc=c;
    //然后对c进行因式分解
    for(ll i=2;i*i<=tc;i++)
    {
        if(tc%i==0)
        {
            ll tmpyz=1;
            int a1=0;
            while(tc%i==0)
            {
                a1++;
                tmpyz *= i;
                tc/=i;
            }
            //然后对这个因子进行处理
            ans *= slove(a,b,tmpyz,i,a1);
            if(ans==0) break;
        }
    }
    if(tc!=1)
    {
        ans *= slove(a,b,tc,tc,1);
    }
    return ans;
}

其实这就是hdu3731了,关于思路可惜不是完全自己想的,稍微瞟了一眼大神的做法,突破了自己原先思维中不敢动c的想法,然后这题就会做了。这题A了也表示数论算是入了个门了,记得XIANBIN5在大一的时候就把数论学完了,并且把这题A了,我还是差太多啊。 接下来就是计算几何了。

以下来自:http://www.cnblogs.com/dyllove98/archive/2013/08/05/3239030.html

求方程:的解个数

 

分析:设,那么上述方程解的个数就与同余方程组:的解等价。

 

设同于方程的解分别是:,那么原方程的解的个数就是

 

所以现在的关键问题是求方程:的解个数。

 

这个方程我们需要分3类讨论:

 

第一种情况:

 

对于这种情况,如果方程的某个解设为,那么一定有,可以得到,即

 

所以方程的解个数就是:,也就是

 

 

第二种情况:

这样也就是说p|B,设,本方程有解的充要条件是A|t,

那么我们设t=kA,

 

所以进一步有:,因为,这样又转化为第三种情况了。

第三种情况:

 

那么我们要求指标;求指标的话又要求原根。并且奇素数p的原根也是p^a的原根,所以说求个p的原根就好了。

且如果有解,则解的个数为(A,φ(p^a))。

 

求指标的话就是要解决A^x ≡ B (mod p^a)的问题。由于本情况保证了(p^a, B)=1,用个Baby-step-Giant-step就

能解决问题。

 

方程x^A ≡ B (mod p^a)有解,当且仅当(A,φ(p^a))|ind B。ind B表示B对于p^a的任一原根的指标。

时间: 2024-12-12 05:55:55

x^a=b(mod c)求解x在[0,c-1]上解的个数模板+原根求法的相关文章

HDU 4622 求解区间字符串中的不同子串的个数

题目大意: 给定一个长度<2000的串,再给最多可达10000的询问区间,求解区间字符串中的不同子串的个数 这里先考虑求解一整个字符串的所有不同子串的方法 对于后缀自动机来说,我们动态往里添加一个字符,每次添加一个字符进去,我们只考虑那个生成的长度为当前长度的后缀自动机的节点 那么这个节点可接收的字符串的个数就是( p->l - p->f->l ),也就是以当前点为最后节点所能得到的与之前不重复的子串的个数 那么这个问题就很好解决了,共2000个位置,以每一个位置为起点构建一次后缀

算法总结之求解模线性方程组

1)求解模线性方程 ax = b(mod n) 方程ax = b(mod n) -> ax = b + ny ->ax - ny = b -> ax + n (-y) =b 其中a,n,b已知. 可用扩展欧几里得来求解该方程的一组特解. 这里给出下列几个定理用来求解方程: 1.当且仅当d|b时,方程ax = b(mod n)有解.d=gcd(a,n) 2.ax = b(mod n) 或者有d个不同解,或者无解. 3.令d=gcd(a,n) 假定对整数x', y', 有d = ax' +

F(X)--c#求解-英雄会在线编程题目

先看题目: F(X) 发布公司: 有 效 期: 赛 区: CSDN 2014-04-16至2015-04-16 北京 难 度 等 级: 答 题 时 长: 编程语言要求: 120分钟 C C++ Java C# 题目详情 我们定义 F(x)是满足 x  mod(a*b) == 0这样的a,b的组数.现在给你一个n,你需要求出 F(n) 输入格式: 多组数据,每组第一行有一个整数n, 0 < n <= 10^11. 输出格式: 每组输出一行,满足条件的(a,b)对数 答题说明 输入样例 1 2 3

【bzoj2219-数论之神】求解x^a==b(%n)-crt推论-原根-指标-BSGS

http://www.lydsy.com/JudgeOnline/problem.php?id=2219 弄了一个晚上加一个午休再加下午一个钟..终于ac..TAT 数论渣渣求轻虐!! 题意:求解 x^A=B(mod n) 在0~n内解的个数.其中1 <= A, B <= 10^9, 1 <= K <= 5 * 10^8  (n=2*K+1) 首先先说这一题的弱化版:bzoj1319 http://www.lydsy.com/JudgeOnline/problem.php?id=1

HDU 4389 X mod f(x) (数位DP)

题目链接  HDU4389 题意  给出T个区间[L, R],统计L到R中有多少个满足条件的数. 限制条件为该数能被这个数的各位数字之和整除. 数据范围$1 <= L <= R <= 10^{9}$ 考虑数位DP 注意到f(x)最大为81,所以对1-81每一个和做一遍数位DP即可. f[pos][mod][sum][x] 表示当前处理到第pos位,当前的数位和对x取模的结果,当前的数位和,以及当前正在求的x = f(x) #include <bits/stdc++.h> us

NOIP2001 一元三次方程求解

题一  一元三次方程求解(20分) 问题描述 有形如:ax3+bx2+cx+d=0  这样的一个一元三次方程.给出该方程中各项的系数(a,b,c,d  均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差的绝对值>=1.要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位. 提示:记方程f(x)=0,若存在2个数x1和x2,且x1<x2,f(x1)*f(x2)<0,则在(x1,x2)之间一定有一个 根. 样例 输入:1  

【Best Coder】#29 B GTY&#39;s birthday gift(快速幂|mod的时候记得负!)

题目大意:查看相关场次即可看到. 思路:推公式的题目,可以用快速幂加公式快速解决,也可以用二进制拆分运算的方法加快速度. 需要注意的一点在于:今后在mod之后有涉及到运算的都要加上一个mod之后再mod,或者统一都加一个mod 顺便复习一下二进制拆分的方法!! 二进制拆分的做法AC代码: #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<algorithm> #include<cstdio> usin

POJ 1061 - 青蛙的约会 - [exgcd求解一元线性同余方程]

先上干货: 定理1: 如果d = gcd(a,b),则必能找到正的或负的整数k和l,使ax + by = d. (参考exgcd:http://www.cnblogs.com/dilthey/p/6804137.html) 定理2: 一元线性同余方程ax ≡ n (mod b) 有解,当且仅当gcd(a,b)|n. 也就是说,解出了ax+by=gcd(a,b),就相当于解出了ax≡n(mod b) (而且只要满足gcd(a,b)|n,就一定有解) 定理3: 若gcd(a,b) = 1,则方程ax

hdu 4389 X mod f(x) 数位dp

题链:http://acm.hdu.edu.cn/showproblem.php?pid=4389 X mod f(x) Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2330    Accepted Submission(s): 919 Problem Description Here is a function f(x): int