【BZOJ 2219】【超详细题解】数论之神

来源:互联网 发布:拼图游戏源码 编辑:程序博客网 时间:2024/04/29 19:46

2219: 数论之神

Time Limit: 3 Sec Memory Limit: 259 MB
Submit: 365 Solved: 33
[Submit][Status][Discuss]
Description

在ACM_DIY群中,有一位叫做“傻崽”的同学由于在数论方面造诣很高,被称为数轮之神!对于任何数论问题,他都能瞬间秒杀!一天他在群里面问了一个神题: 对于给定的3个非负整数 A,B,K 求出满足 (1) X^A = B(mod 2*K + 1) (2) X 在范围[0, 2K] 内的X的个数!自然数论之神是可以瞬间秒杀此题的,那么你呢?

Input

第一行有一个正整数T,表示接下来的数据的组数( T <= 1000) 之后对于每组数据,给出了3个整数A,B,K (1 <= A, B <= 10^9, 1 <= K <= 5 * 10^8)

Output

输出一行,表示答案

Sample Input

3

213 46290770 80175784

3 46290770 80175784

3333 46290770 80175784

Sample Output

27

27

297
HINT

新加数组一组–2015.02.27

Source

数论 鸣谢 AekdyCoin

中国剩余定理+阶+原根+指标+扩展欧几里得~

首先说说概念:

1.【阶】
满足ax1(modp) 的最小的xa关于p的阶。
记作δ(a)=x

2.【原根】
δ(g)=φ(p),则称gp的原根。

(1)只有1,2,4,pk,2pkp是奇素数)有原根。

(2)p的原根个数为φ(φ(p))
(证明见这里)

(3)p>1,φ(p)所有不同的因数为p1,p2,,pk(g,m)=1,则g是模p的原根的充要条件是:gpi1(modp)对于所有的pi都不成立
(这也是原根的求法)

3.【指标】
gra(modp)成立,则称r是以g为底的a对模m的一个指标。
记作r=inda

(1)ab(modp)indaindb(modφ(p))

(2)ind(ab)inda+indb(modφ(p))

(3)ind(an)ninda(modφ(p))

(4)指标的求法:
先求出p的原根g,然后用BSGS求出gab(modp)中的a
(BSGS详见这里)

接下来说这道题。。

求方程xAB(modP)的解的个数。

P=pa11pa22pakk,那么原方程的解的个数就是xAB(modpaii)的解的个数的乘积。

为什么呢?

对于每一个xAB(modpaii)方程我们从中选出一个解xi

可以求出xi mod paii的解为wi

设原方程的解为X,则Xwi(modpaii)

于是形成了k个同余方程,根据中国剩余定理,一组同余方程对应一个X的解。

那么一共有xAB(modpaii)的解的个数的乘积个选法,就有对应的这么多的解。

于是问题变成了求xAB(modpa)的解的个数。

分三种情况讨论:

1.(pa,B)=B

此时原方程变成了

xA0(modpa)

x=pt,那么要求tAa
那么最小的t=a1A+1
此方程的解的个数为

pa(a1A+1)

2.(pa,B)>1

B=pcntb,原方程变为

xApcntb(modpa)

(1)如果cnt mod A0,此方程无解。
(2)否则把方程转化为

(xpcntA)Ab(modpacnt)

由于此时(pacnt,b)=1,方程转化成了第三种情况~

仅仅这样做是不够的!
在原式中x的取值范围是[0,pa),那么xpcntA的取值范围就是[0,pacntA)

可是在后一个式子中xpcntA的取值范围变成了[0,pacnt)!!

因此我们需要在结果之后乘上pcntcntA

3.(pa,B)=1

此时的方程是

xAB(modpa)

我们利用前面说的指标的性质可以将此方程转化为
AindxindB(modφ(pa))

利用BSGS求出indB,又因为indx对应着一个x,那么方程就变成了
axb(modp)

原方程解的个数对应上面那个方程的解的个数!!
(1)如果b mod gcd(a,p)0则无解;
(2)否则解的个数为gcd(a,p)

吼吼,第一次用Mathjax和markdown写博客~

#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <cmath>#include <cstdlib>#define inf 1e17#define LL long long#include <map>using namespace std;map<LL,LL> mp;struct data{    LL p,c,pc;}a[100005];int num,cnt;LL f[100005];void Chai(int x){    num=0;    for (int i=2;i<sqrt(x+0.5);i++)        if (x%i==0)        {            a[++num].p=i;            a[num].c=0,a[num].pc=1;            while (x%i==0)                x/=i,a[num].c++,a[num].pc*=i;            if (x==1) break;        }    if (x!=1)        a[++num].p=x,a[num].pc=x,a[num].c=1;}LL Pow(LL x,LL n,LL mod){    LL ans=1,b=x;    while (n)    {        if (n&1)            ans=ans*b%mod;        b=b*b%mod;        n>>=1LL;    }    return ans;}LL GetPrimitiveRoot(LL p,LL phi){    int c=0;    for (int i=2;i*i<=phi;i++)        if (phi%i==0)            f[++c]=i,f[++c]=phi/i;    for (int g=2;;g++)    {        int j;        for (j=1;j<=c;j++)            if (Pow(g,f[j],p)==1) break;        if (j==c+1) return g;    }    return 0;}void exgcd(LL a,LL b,LL &d,LL &x,LL &y){    if (!b)    {        d=a,x=1,y=0;        return;    }    exgcd(b,a%b,d,y,x);    y-=x*(a/b);}LL BSGS(LL A,LL B,LL C){    int m=ceil(sqrt(C+0.5));    mp.clear();    LL now=1;    for (int i=1;i<=m;i++)    {        now=now*A%C;        if (!mp[now]) mp[now]=i;    }    mp[1]=0;    A=Pow(A,m,C);    now=1LL;    for (int i=0;i<=m;i++)    {        LL d,x,y;        exgcd(now,C,d,x,y);        x=(x*B%C+C)%C;        if (mp.count(x)) return i*m+mp[x];        now=now*A%C;    }    return 0;}LL Gcd(LL a,LL b){    if (!b) return a;    return Gcd(b,a%b);}LL Solve(LL A,LL B,LL k){    LL phi=a[k].pc-a[k].pc/a[k].p,g=GetPrimitiveRoot(a[k].pc,phi);    LL ind=BSGS(g,B,a[k].pc);    LL ans=Gcd(phi,A);    if (ind%ans) return 0;    return ans*Pow(a[k].p,cnt-cnt/A,inf);}int main(){    int T;    scanf("%d",&T);    while (T--)    {        LL A,B,k;        scanf("%lld%lld%lld",&A,&B,&k);        LL p=2*k+1;        Chai(p);        LL ans=1;        for (int i=1;i<=num;i++)        {            if (!ans) break;            if (B%a[i].pc==0)                ans=ans*Pow(a[i].p,a[i].c-(a[i].c-1)/A-1,inf);            else            {                int b=B;                cnt=0;                while ((b%a[i].p)==0)                    b/=a[i].p,                    a[i].pc/=a[i].p,                    a[i].c--,cnt++;                if (cnt%A) ans=0;                else ans=ans*Solve(A,b,i);            }        }        printf("%lld\n",ans);    }    return 0;}

这里写图片描述

感悟:

1.WA是因为求原根的地方我没有对p取模

2.分类讨论+原根和指标的应用~

3.UPD:
①a关于p的阶x为什么一定是φ(p)的因数?

假设p=kx+rr0 r<x,那么axar1(modp),与阶的定义(最小的模p1的数)矛盾

p与他的原根g一定互质吗?

一定的。
原根与欧拉定理aφ(p)1(modp)是密不可分的,欧拉定理规定(a,p)=1

如果(a,p)=kk>1,那么(aφ(p),p)=(p,aφ(p)%p)k
显然不符合欧拉定理。

③为什么p的原根一定是pa的原根??

2 0
原创粉丝点击