洛谷 P10704 救赎(Redemption)

洛谷传送门

不依赖 \(a_i \le 10^9\) 的做法。

\(b_x\) 为有多少个 \(i\) 使得 \(a_i = x\)

设一个阈值 \(B\)。当 \(\frac{m}{a_i a_j} > B\)\(a_i a_j < \frac{m}{B}\),可以直接枚举 \(a_i\)\(a_j\) 然后利用 \(b\) 数组统计。这部分时间复杂度为 \(O(\frac{m}{B} \ln \frac{m}{B})\)

\(\frac{m}{a_i a_j} \le B\) 时,统计 \(\left\lfloor\frac{m}{a_i a_j}\right\rfloor\) 之和可以转化为对于一个整数 \(k \in [1, B]\),有多少对 \((i, j)\) 满足 \(x \le \frac{m}{a_i a_j}\)\(x \cdot a_i \cdot a_j \le m\)。可以排序后双指针统计。这部分时间复杂度为 \(O(nB)\)

总时间复杂度为 \(O(\frac{m}{B} \ln \frac{m}{B} + nB)\)。取 \(B = 350\) 可以通过。

code
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 1000100;
const int N = 30000000;
const ll mod = 998244353;

ll n, m, a[maxn], b[N + 5];

void solve() {
	scanf("%lld%lld", &n, &m);
	for (int i = 1; i <= n; ++i) {
		scanf("%lld", &a[i]);
		if (a[i] <= N) {
			++b[a[i]];
		}
	}
	sort(a + 1, a + n + 1);
	ll ans = 0;
	for (int i = 1; i <= N; ++i) {
		if (!b[i]) {
			continue;
		}
		for (int j = 1; i * j <= N; ++j) {
			if (b[j]) {
				ll x = m / i / j;
				if (x <= 350) {
					continue;
				}
				x %= mod;
				ans = (ans + b[i] * b[j] % mod * x) % mod;
			}
		}
	}
	for (int x = 1; x <= 350; ++x) {
		for (int i = n, j = 0, k = 1; i; --i) {
			while (j < n && x * a[i] * a[j + 1] <= m) {
				++j;
			}
			while (k <= n && a[i] * a[k] * 351 <= m) {
				++k;
			}
			ans += j - k + 1;
		}
	}
	printf("%lld\n", ans % mod);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2024-07-07 16:26  zltzlt  阅读(33)  评论(0编辑  收藏  举报