HDU 6889 Graph Theory Class (Min25筛)

题意:n个点的完全图,边权为lcm(i+1, j+1),求mst。

题解:Min25筛
质数与2连,其他点与最小因子连,那么只要求n以内质数和即可。

比赛的时候本来想用区间筛打表的,这题其实套个Min25筛就好了,因为1e10,用int128存质数和,避免取模,结果调了一个下午,居然是n为1没输出。

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pii pair
using namespace std;
int t, mod;
ll n;
void print(__int128 x) {
	if (!x) return;
	if (x < 0) putchar('-'), x = -x;
	print(x / 10);
	putchar(x % 10 + '0');
}
const int N = 3400005;
int pt[N], pri[N >> 2], tot = 0;
ll sum[N];
inline void init() {
	for (int i = 2; i <= N - 5; i++) {
		sum[i] = sum[i - 1];
		if (!pt[i]) pri[++tot] = i, sum[i] += i;
		for (int j = 1; j <= tot && i * pri[j] <= N - 5; j++) {
			pt[i * pri[j]] = 1;
			if (i % pri[j] == 0) break;
		}
	}
}
inline __int128 S(ll x) { return (__int128)x * (x + 1) / 2; }
int cnt, t1[N], t2[N];
ll last[N << 1];
__int128 h[N << 1];
inline __int128 calc(ll x) {
	cnt = 0;
	int id; ll l, r, t;
	for (l = 1; l <= x; l = r + 1) {
		t = (x / l); r = x / t; last[++cnt] = t; h[cnt] = S(t) - 1;
		(t >= N - 5 ? t2[x / t] : t1[t]) = cnt;
	}
	for (int j = 1; j <= tot; j++) {
		ll pw = (ll)pri[j] * pri[j];
		if (pw > x) break;
		for (int i = 1; i <= cnt && last[i] >= pw; i++) {
			t = last[i] / pri[j], id = t >= N - 5 ? t2[x / t] : t1[t];
			h[i] -= (__int128)pri[j] * (h[id] - sum[pri[j] - 1]);
		}
	}
	return h[x >= N - 5 ? t2[1] : t1[x]];
}

int main() {
	init();
	scanf("%d", &t);
	while (t--) {
		scanf("%lld%d", &n, &mod);
		++n;
		if (n == 2) {
			puts("0");
			continue;
		}
		ll x = n + 3;
		ll y = n - 3 + 1;
		if ((n + 3) & 1) y /= 2;
		else x /= 2;
		__int128 ans = (x % mod) * (y % mod) % mod;
		ans += calc(n) - 2;
		ans %= mod;
		print(ans);
		puts("");
	}
	return 0;
}

你可能感兴趣的:(数论,Min25筛)