AtCoder Beginner Contest 212 G Power Pair

洛谷传送门

AtCoder 传送门

\(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;
}

posted @ 2023-05-18 15:43  zltzlt  阅读(30)  评论(0编辑  收藏  举报