题目链接:https://codeforces.com/problemset/problem/919/E
题意: 给出a,b,p,x(2 <= p <= 1e6+3, 1<= a, b < p, 1<= x <= 1e12) 保证p是素数.求1到x中满足方程 (n*a^n) % p = b的解的个数.
思路: 由费马小定理知道 a^(p-1) % p = 1, 所以(n*a^n) % p 等于 (n%p)*a^(n%(p-1)). 那我们可以枚举n%(p-1)的值,来算出对应的解的个数. 设此时 n % (p-1) = i, (a^i)对应p的逆元为c, n % p = (b*c%p) 这样我们就得到了两个方程, 此时就可以用中国剩余定理求解. 且我们发现一个周期内最多只会有一个解.
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e6+5;
ll a, b, p, xx;
ll poww[maxn], m[2], ai[2];
ll pow_mod(ll t, ll k) {
ll ans = 1;
while(k) {
if(k & 1) ans = ans * t % p;
t = t * t % p;
k >>= 1;
}
return ans;
}
void exgcd(ll a, ll b, ll& d, ll& x, ll& y) {
if(!b) {
x = 1;
y = 0;
d = a;
}
else {
exgcd(b, a%b, d, y, x);
y -= (a/b)*x;
}
}
void init() {
poww[0] = 1;
for(int i = 1; i < p-1; i++)
poww[i] = poww[i-1] * a % p;
}
ll CRT(int n) {
ll mul = 1, ans = 0, d, x, y;
for(int i = 0; i < n; i++)
mul *= m[i];
for(int i = 0; i < n; i++) {
ll mi = mul/m[i];
exgcd(mi, m[i], d, x, y);
ans = (ans + ai[i]*mi*x%mul)%mul;
}
ans = (ans%mul+mul)%mul;
return xx/(p*(p-1)) + ((xx%(p*(p-1))) >= ans);
}
int main() {
cin >> a >> b >> p >> xx;
a = pow_mod(a, p-2);
m[0] = p, m[1] = p-1;
init();
ll ans = 0;
for(int i = 0; i < p-1; i++) {
ai[0] = (b*poww[i])%p;
ai[1] = i;
ans += CRT(2);
}
cout << ans << endl;
}