特别像bzoj的那一道“数论之神”(准确的说应该是加强版),首先我们考虑当B是素数时我们怎么做。
显然我们只要求出一个原根g,然后求出C的指标,就能将问题转化为AindX≡indC(mod B-1)的问题 在问题保证了解的数量不超过sqrt(B)的情况下 可以O(B^0.5)求解。
然后我们会发现上面的做法是可以推广的,只要在mod B意义下存在原根(B为1,2,4,p,2p或p^k,p为奇素数,这里只考虑p^k的情况),我们就可以闷声大讨论,得到所有的解了。
具体来说分为三类:(B=p^k)
1. gcd(C,B)=1 可以直接用上面的方法
2. C≡0(mod B) 这时只要令x中p的项为s次,满足As>=k即可,也很好求解
3. C≡p^a*d 此时显然存在A|a 这时显然我们可以求出A'=A B'=p^(k-a) C'=d时的所有x 最后满足条件的x就是这样的x+mp^(k-a+a/A)
然后我们发现我们还会做B为奇数时候的情况 我们可以对B质因数分解 对于每个pi^ki分别做一次 根据中国剩余定理,每一组这样的解都对应了一组最终的解 且最终的解也一定满足在mod pi^ki时也满足条件 这样我们求出每一个部分的解 CRT合并即可。
可是问题来了 当2^k|B时 我们应该如何解决这样的问题呢?
下午问了好多人 感觉大家都不是太会 找了标程才发现原来有一种基于解的个数的做法。
考虑x^A ≡ C(mod 2^k)
那么显然也有x^A ≡ C(mod 2^(k-1))
假设我们已经求出了x^A ≡ C(mod 2^(k-1))的所有解x
就可以对每个x和x+2^(k-1)暴力判定是否满足要求 就相当于对x进行了一次二进制分组
当解的个数为S时,这样的时间复杂度为O(kSlogB)的
为什么这样做的复杂度是正确的 而不会造成某一层可行解过多 而下一层却都不可行呢?
我们考虑 x^A ≡ C (mod 2^k) 和 x^A ≡ C (mod 2^(k-1)) 的解数
我们带入 x和 x+2^(k-1) 发现有对于
x^A ≡ C 和 (x+2^(k-1))^A ≡ C 的判定
而 (x+2^(k-1))^A ≡ x^A + x^(A-1)2^(k-1) ≡ x^A + (x mod 2)2^(k-1)
因此当x为奇数时 x和x+2^(k-1) 中有且仅有一解
而当x为偶数 通过大量打表验证(其实是我不会证)我们发现是正确的!
所以就O(跑得过)???
#include"bits/stdc++.h"
using namespace std;
const int N=40005,hmod=1000003,INF=0x7fffffff;
typedef pair<int,int> pii;
typedef long long LL;
struct HashMap{
int h[hmod+5],nxt[N],val[N],flag[N],ndc,flag_NULL;
HashMap(){ndc=flag_NULL=0;}
int&find(int x){
for(int i=h[x%hmod];i;i=nxt[i])
if(flag[i]==x)return val[i];
return flag_NULL;
}
int&operator[](int x){
int&q=find(x);
if(q)return q;
nxt[++ndc]=h[x%hmod],h[x%hmod]=ndc,flag[ndc]=x;
return val[ndc];
}
void clear(){
while(ndc){
h[flag[ndc]%hmod]=0;
val[ndc]=nxt[ndc]=flag[ndc]=0;
ndc--;
}
}
}F;
int gcd(int x,int y){return y?gcd(y,x%y):x;}
int power(int a,int t,int P){
int r=1;
while(t){
if(t&1)r=(LL)r*a%P;
a=(LL)a*a%P;t>>=1;
}
return r;
}
int bsgs(int g,int mod,int r,int lim){
F.clear();
int S=sqrt(lim),l=1,m=1;
for(int i=0;i<S;i++)F[l]=i,l=(long long)l*g%mod;
l=power(l,lim-1,mod);
for(int i=0;i*S<=lim;i++){
if((long long)r*m%mod==1)return i*S;
int x=F.find((long long)r*m%mod);
if(x)return i*S+x;
m=(long long)m*l%mod;
}
return -1;
}
bool chc(int g,int l,int mo){
int r=l;
for(int i=2;i*i<=r;i++)if(r%i==0){
while(r%i==0)r/=i;
if(power(g,l/i,mo)==1)return false;
}
if(r>1)return power(g,l/r,mo)!=1;
return true;
}
void exgcd(int a,int b,LL&x,LL&y){
if(b==0){x=1,y=0;return;}
exgcd(b,a%b,y,x);y-=a/b*x;
}
int T,a,P,r,x[10][N],y[N],tmp[N],bs[10],ti[10],l;
void solve(int k,int a,int r,int p,int t){
if(p==2){
y[++y[0]]=r&1;
for(int i=1;i<=t;i++){
int mo=1<<i,dl=mo>>1;
tmp[0]=0;
for(int j=1;j<=y[0];j++){
if(power(y[j],a,mo)==r%mo)tmp[++tmp[0]]=y[j];
if(power(y[j]+dl,a,mo)==r%mo)tmp[++tmp[0]]=y[j]+dl;
}
memcpy(y,tmp,tmp[0]+1<<2);
}
memcpy(x[k],y,y[0]+1<<2);
return;
}
int mo=power(p,t,INF);
r%=mo;
y[0]=0;
if(r==0){
int b=power(p,(t+a-1)/a,INF);
x[k][0]=mo/b;
for(int i=1;i<=x[k][0];i++)x[k][i]=b*(i-1);
return;
}
if(r%p==0){
int _r=r,qt=0,_m,_k;
while(_r%p==0)++qt,_r/=p;
if(qt%a){x[k][0]=0;return;}
solve(k,a,_r,p,t-qt);
y[0]=0;
_m=power(p,t-qt+qt/a,INF),_k=r/_m;
for(int i=1;i<=x[k][0];i++)for(int j=0;j<_k;j++)y[++y[0]]=j*_m+x[k][i];
memcpy(x[k],y,y[0]+1<<2);
return;
}
int g,ri=mo/p*(p-1);
if(chc(2,ri,mo))g=2;else for(g=3;!chc(g,ri,mo);++g);
int ind=bsgs(g,mo,r,ri),_a=a;
a=gcd(ri,a);
if(ind%a){x[k][0]=0;return;}
LL _x,_y;
exgcd(_a,ri,_x,_y);
_x=(_x%ri*ind/a%ri+ri)%ri;
x[k][0]=a;
int fi=power(g,_x,mo),mi=power(g,ri/a,mo);
for(int i=1;i<=a;i++)x[k][i]=fi,fi=(LL)fi*mi%mo;
}
int ans[N];
int CRT(int r1,int m1,int r2,int m2){
LL x,y,z=m1*m2;exgcd(m1,m2,x,y);
return ((x%z*(r2-r1)%z*m1+r1)%z+z)%z;
}
void dfs(int p,int r,int mo){
if(p==l+1){ans[++ans[0]]=r;return;}
int _mo=power(bs[p],ti[p],INF);
for(int i=1;i<=x[p][0];i++)dfs(p+1,CRT(r,mo,x[p][i],_mo),mo*_mo);
}
void work(){
int _P=P;
l=0;
if(P==1){puts("0");return;}
for(int i=2;i*i<=_P;i++)if(_P%i==0){
int t=0;
while(_P%i==0)_P/=i,++t;
bs[++l]=i,ti[l]=t;
solve(l,a,r,i,t);
if(x[l][0]==0){puts("No Solution");return;}
}
if(_P>1){
bs[++l]=_P,ti[l]=1,solve(l,a,r,_P,1);
if(x[l][0]==0){puts("No Solution");return;}
}
ans[0]=0;
if(l==1)memcpy(ans,x[1],x[1][0]+1<<2);
else for(int i=1,m=power(bs[1],ti[1],INF);i<=x[1][0];i++)dfs(2,x[1][i],m);
int n=ans[0];
sort(ans+1,ans+n+1);
for(int i=1;i<=n;i++)printf("%d%c",ans[i]," \n"[i==n]);
}
int main(){
scanf("%d",&T);
while(T--)scanf("%d%d%d",&a,&P,&r),work();
return 0;
}