1 条题解
-
0
方法一
设 ,当 不能被表示为 的形式时,考虑对其进行中国剩余定理分解为 ,那么只要对每个 分别处理出答案后直接乘起来就好了。
问题转化求 的个数。
分情况讨论一下。
假设 ,那么需要满足 。
。
所以方程的解得个数为
令 表示原根,设 。
所以 。
此时可以求出 ,就直接解同余方程
先判断是否有解,如果有解,解的个数就是 。
假设 。
那么
此时必然满足 是 的倍数,否则无解。
转化为
$$(\frac{x}{p^{\frac{Z}{A}}})^A\equiv b \pmod{P^{q-Z}} $$直接变成第二种情况。
记住此时答案需要乘 。
方法二
上面一种方法的时间复杂度是 且常数比较大,原题可以过,但会被卡掉。
考虑优化找 这个过程。
考虑通过原根将 放到一个圆上,圆上有 个值,。
那么实际上只要找到 在哪个位置就好了。
但这十分困难,但我们有一个比较好求一点的,令 。
那么 有什么用呢?
考虑 一共会在圆上占 个位置,且这些位置均匀分布,所以可以求出两个位置之间的距离为 。
令 ,那么必然满足 是 的原根,不然不可能取到全部 个点。
然后就发现了一个重要结论, 也是原根,因为它也可以去到所有的点。
那么直接令 为新的原根,此时 。
然后就得到了一个 直接求解就好了。
代码
#include<bits/stdc++.h> using namespace std; struct Prime{int p,pt,t;}a[50];//p表示素数,pt表示p^t,t表示P中含有多少个p int tot,_; void spilt(int p){ tot=0; for(int i=2;i*i<=p;i++) if(p%i==0){ a[++tot].p=i,a[tot].pt=1,a[tot].t=0; for(;p%i==0;p/=i)a[tot].pt*=i,a[tot].t++; } if(p>1) a[tot].p=a[++tot].pt=p,a[tot].t=1; } int kuai(int a,int b,int mod){//快速幂 int ans=1; for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)ans=1ll*ans*a%mod; return ans; } int get_Step(int a,int n,int mod){//求阶 int ans=n; for(int i=2;i*i<=n;i++) if(n%i==0){ while(ans%i==0&&kuai(a,ans/i,mod)==1)ans/=i; for(;n%i==0;n/=i); } if(kuai(a,ans/n,mod)==1)ans/=n; return ans; } int ans; void solve(int A,int B,int mod,int phi){ int c=get_Step(B,phi,mod),y=phi/c,G=__gcd(A,phi); if(y%G)ans=0; ans*=G; } int main(){ scanf("%d",&_); while(_--){ int A,B,k; scanf("%d%d%d",&A,&B,&k); int P=2*k+1; B%=P; ans=1; spilt(P);//先将P分解质因数 for(int i=1;i<=tot;i++){ int p=a[i].p,t=a[i].t,pt=a[i].pt; if(!ans)break; if(B%pt==0) ans*=kuai(p,t-(t+A-1)/A,1e9); else{ int Z=0,b=B; for(;b%p==0;Z++,pt/=p,t--,b/=p); if(Z%A)ans=0; else{ solve(A,b,pt,pt-pt/p); ans*=kuai(p,Z-Z/A,1e9); } } } printf("%d\n",ans); } }
- 1
信息
- ID
- 2219
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 7
- 标签
- (无)
- 递交数
- 19
- 已通过
- 9
- 上传者