AtCoder Beginner Contest 212 G Power Pair
设 \(P\) 的原根为 \(g\),那么 \(x,y\) 可以表示成 \(g^a, g^b\) 的形式(特判 \(x = y = 0\))。那么要求 \(an \equiv b \pmod {P - 1}\),其中 \(a,b \in [1, P - 1]\)。
考虑固定 \(a\),可以把问题看成,有 \(P - 1\) 个点的环,点编号 \(1 \sim P - 1\),从 \(1\) 开始每次跳 \(a\) 步,跳到的本质不同点数。这是经典问题,考虑循环节即 \(\frac{P - 1}{\gcd(P - 1, a)}\),所以本质不同点数是 \(\frac{P - 1}{\gcd(P - 1, a)}\)。下文令 \(n = P - 1\)。
于是现在要求 \(\sum\limits_{x=1}^n \frac{n}{\gcd(n, x)}\)。考虑求出 \(n\) 的所有因数 \(a_1, a_2, ..., a_m\),设 \(f_i\) 为 \(\sum\limits_{x=1}^n [\gcd(x, n) = a_i]\),那么 \(f_i\) 可容斥得出,即 \(f_i = \frac{n}{a_i} - \sum\limits_{j \in [i+1, m] \land a_i \mid a_j} f_j\),那么最终答案就是:
\[ans = \sum\limits_{i=1}^m f_i \times \frac{n}{a_i}
\]
时间复杂度 \(O(\sqrt{P} + d(n)^2)\),其中 \(d(n)\) 为 \(n\) 的因数个数。
code
// Problem: G - Power Pair
// Contest: AtCoder - AtCoder Beginner Contest 212
// URL: https://atcoder.jp/contests/abc212/tasks/abc212_g
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 7000;
const ll mod = 998244353;
ll n, a[maxn], m, f[maxn];
void solve() {
scanf("%lld", &n);
--n;
for (ll i = 1; i * i <= n; ++i) {
if (n % i) {
continue;
}
a[++m] = i;
if (i * i != n) {
a[++m] = n / i;
}
}
sort(a + 1, a + m + 1);
ll ans = 1;
for (int i = m; i; --i) {
f[i] = n / a[i] % mod;
for (int j = i + 1; j <= m; ++j) {
if (a[j] % a[i] == 0) {
f[i] = (f[i] - f[j] + mod) % mod;
}
}
ans = (ans + f[i] * (n / a[i] % mod) % mod) % mod;
}
printf("%lld\n", ans);
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}