bzoj2219(离散对数+CRT)

题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=2219

题解

模数是奇数应该是为了保证原根的存在。。

设原方程解为 $X$

然后由于模数可以为合数所以要用 $CRT$ 分解,类似

设其解为 $w_1,w_2…w_j$ ,那么

必有且仅有一个成立

这样可以组成若干个方程组,根据 $CRT$ 一个方程组在模数范围内仅有一解,那么解的个数即为方程组的个数,所以只需要计算每个方程组的解集大小,直接相乘即可。。

回到

此时模数不是质数,不能直接求对数

当 $(b,p^k)=1$ ,此时可以直接求对数后求解,若存在解,那么解个数为 $gcd((p-1)p^{k-1},a)$

当 $b%p^k=0$ ,那么 $x=Cp^t$ ,那么 $at\geq k$ ,所以 $t=\left\lceil \frac{k}{a} \right\rceil$

那么解个数为

当 $1<(b,p^k)<p^k$ ,令 $b=Bp^{cnt}$ ,那么

此时满足 $a|cnt$ 才有解,然后就可以求离散对数了。。

但是解集的范围均落在 $[0,p^{k-cnt})$ 之间,那么需要将解集扩大到 $[0,p^{k-\frac{cnt}{a}})$ ,所以方案数要乘上 $p^{cnt-\frac{cnt}{a}}$

相当考验板子。。




代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/**
*         ┏┓    ┏┓
*         ┏┛┗━━━━━━━┛┗━━━┓
*         ┃       ┃  
*         ┃   ━    ┃
*         ┃ >   < ┃
*         ┃       ┃
*         ┃... ⌒ ...  ┃
*         ┃ ┃
*         ┗━┓ ┏━┛
*          ┃ ┃ Code is far away from bug with the animal protecting          
*          ┃ ┃ 神兽保佑,代码无bug
*          ┃ ┃           
*          ┃ ┃       
*          ┃ ┃
*          ┃ ┃           
*          ┃ ┗━━━┓
*          ┃ ┣┓
*          ┃ ┏┛
*          ┗┓┓┏━━━━━━━━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<set>
#include<bitset>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 1000005
#define nm 1025
#define pi 3.1415926535897931
using namespace std;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}






int _x,_y,b[40],c[40],_t,p,tot;
ll inf,ans;
ll qpow(ll x,ll t){return t?qpow(sqr(x)%inf,t>>1)*(t&1?x:1ll)%inf:1ll;}
ll exgcd(ll a,ll b,ll&x,ll&y){
if(b==0){x=1;y=0;return a;}
ll t=exgcd(b,a%b,y,x);y-=a/b*x;return t;
}

int gen(int n){
//m=phi(n)
int m=n/_t*(_t-1),cnt=m,tot=0,c[40];
for(int i=2;i*i<=m;i++)if(m%i==0){
c[++tot]=cnt/i;
while(m%i==0)m/=i;
}
if(m>1)c[++tot]=cnt/m;
inc(i,1,n){
bool f=true;
inc(j,1,tot)if(qpow(i,c[j])==1){f=false;break;}
if(f)return i;
}
}

ll bsgs(ll a,ll b){
map<int,int>v;int n=sqrt(inf)+1,ans=inf;
ll inv,t;exgcd(a,inf,inv,t);inv%=inf;if(inv<0)inv+=inf;t=qpow(a,n);
for(int i=0;i<n;i++,b=b*inv%inf)if(!v.count(b))v[b]=i;
for(int i=0,k=1;i<=n;i++,k=k*t%inf)if(v.count(k))ans=min(ans,v[k]+i*n);
return ans;
}

ll solve(ll a,ll b){
int s=0;
if(b==0){
while(inf>1)s++,inf/=_t;
inf=1e9;
return qpow(_t,s-1-(s-1)/a);
}
while(b%_t==0){
b/=_t;inf/=_t;s++;
}
if(s%a)return -1;
int g=gen(inf),indb=bsgs(g,b);
ll x,y;ll t=exgcd(a,inf/_t*(_t-1),x,y);
if(indb%t)return -1;
inf=1e9;t*=qpow(_t,s-s/a);return t;
}

int main(){
int _=read();while(_--){
_x=read();_y=read();p=read()<<1|1;tot=0;
for(int i=3;i*i<=p;i++)if(p%i==0)
for(c[++tot]=1,b[tot]=i;p%i==0;p/=i)c[tot]*=i;
if(p>2)c[++tot]=p,b[tot]=p;
ans=1;
inc(i,1,tot){
inf=c[i];_t=b[i];
ll t=solve(_x,_y%inf);
if(t==-1){ans=-1;break;}
ans*=t;
}
if(ans==-1)printf("0\n");else printf("%lld\n",ans);
}
return 0;
}