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.【阶】
满足 ax≡1(modp) 的最小的 x 是 a 关于 p 的阶。
记作 δ(a)=x
2.【原根】
若 δ(g)=φ(p) ,则称 g 是 p 的原根。
(1)只有 1,2,4,pk,2∗pk ( p 是奇素数)有原根。
(2) p 的原根个数为 φ(φ(p))
(证明见这里)
(3) p>1 , φ(p) 所有不同的因数为 p1,p2,…,pk , (g,m)=1 ,则 g 是模 p 的原根的充要条件是: gpi≡1(modp) 对于所有的 pi 都不成立
(这也是原根的求法)
3.【指标】
若 gr≡a(modp) 成立,则称 r 是以 g 为底的 a 对模 m 的一个指标。
记作 r=inda
(1) a≡b(modp)⇔inda≡indb(modφ(p))
(2) ind(a∗b)≡inda+indb(modφ(p))
(3) ind(an)≡n∗inda(modφ(p))
(4)指标的求法:
先求出 p 的原根 g ,然后用BSGS求出 ga≡b(modp) 中的 a
(BSGS详见这里)
设 P=pa11pa22…pakk ,那么原方程的解的个数就是 xA≡B(modpaii) 的解的个数的乘积。
为什么呢?
对于每一个 xA≡B(modpaii) 方程我们从中选出一个解 xi 。
可以求出 xi mod paii 的解为 wi 。
设原方程的解为 X ,则 X≡wi(modpaii) 。
于是形成了 k 个同余方程,根据中国剩余定理,一组同余方程对应一个 X 的解。
那么一共有 xA≡B(modpaii) 的解的个数的乘积个选法,就有对应的这么多的解。
分三种情况讨论:
此时原方程变成了
设 x=pt ,那么要求 t∗A≥a 。
那么最小的 t=⌊a−1A⌋+1 。
此方程的解的个数为
设 B=pcnt∗b ,原方程变为
(1)如果 cnt mod A≠0 ,此方程无解。
(2)否则把方程转化为
由于此时 (pa−cnt,b)=1 ,方程转化成了第三种情况~
⋆⋆⋆ 仅仅这样做是不够的!
在原式中 x 的取值范围是 [0,pa) ,那么 xpcntA 的取值范围就是 [0,pa−cntA) ;
可是在后一个式子中 xpcntA 的取值范围变成了 [0,pa−cnt) !!
因此我们需要在结果之后乘上 pcnt−cntA
此时的方程是
吼吼,第一次用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+r 且 r≠0 r<x ,那么 ax≡ar≡1(modp) ,与阶的定义(最小的模 p 余 1 的数)矛盾
② p 与他的原根 g 一定互质吗?
一定的。
原根与欧拉定理 aφ(p)≡1(modp) 是密不可分的,欧拉定理规定 (a,p)=1 。
如果 (a,p)=k 且 k>1 ,那么 (aφ(p),p)=(p,aφ(p)%p)≥k 。
显然不符合欧拉定理。
③为什么 p 的原根一定是 pa 的原根??