AtCoder Regular Contest 135 E Sequence of Multiples

发布时间 2023-05-08 14:11:11作者: zltzlt

洛谷传送门

AtCoder 传送门

技巧性比较强的题(?

\(a\) 为最优解的 \(A\),则 \(a\) 可以贪心构造,就是每一位都取到下界。

考虑设 \(b_i = \frac{a_i}{i}\),因为 \(i \times b_i < (i + 1) \times b_{i+1}\),则 \(b_{i+1} = \left\lfloor\frac{i \times b_i}{i+1}\right\rfloor + 1 = b_i - \left\lceil\frac{b_i}{i+1}\right\rceil + 1\),得到 \(b_i - b_{i+1} = \left\lceil\frac{b_i}{i+1}\right\rceil - 1\),所以 \(b\) 不增。

考虑 \(b_i\) 一个比较宽松的上界:

\[\because a_i \le X + \sum\limits_{j=2}^i j = X - 1 + \frac{i(i+1)}{2} < X + i^2 \]

\[\therefore b_i < \frac{X}{i} + i \]

发现 \(b_i\) 的减小速度大致会越来越平缓。考虑类根号分治,观察 \(b_i - b_{i+1}\),发现它只有 \(O(X^{\frac{1}{3}})\) 种取值。证明:

  • \(i \le X^{\frac{1}{3}}\)\(b_i - b_{i+1}\)\(O(X^{\frac{1}{3}})\) 种取值;
  • \(i > X^{\frac{1}{3}}\)\(b_i - b_{i+1} = \left\lceil\frac{b_i}{i+1}\right\rceil - 1 < \left\lceil\frac{\frac{X}{i}+i}{i+1}\right\rceil = O(X^{\frac{1}{3}})\),有 \(O(X^{\frac{1}{3}})\) 种取值。

考虑对极长等差连续段 \([l,r]\) 计算。设 \(b_l - b_{l+1} = b_{l+1} - b_{l+2} = \cdots = b_{r-1} - b_r = k\),我们希望计算 \(\sum\limits_{i=l}^r a_i\)

\[\sum\limits_{i=l}^r a_i \]

\[= \sum\limits_{i=1}^r i \times b_i \]

\[= \sum\limits_{i=l}^r i \times (b_l + (l - i) \times k) \]

\[= \sum\limits_{i=l}^r i \times b_l + i \times (l - i) \times k \]

\[= \sum\limits_{i=l}^r i \times (b_l + k \times l) - k \times i^2 \]

\(f(x) = \sum\limits_{i=1}^x i = \frac{i(i+1)}{2}\)\(g(x) = \sum\limits_{i=1}^x i^2 = \frac{i(i+1)(2i+1)}{6}\),得到:

\[\sum\limits_{i=l}^r i \times (b_l + k \times l) - k \times i^2 \]

\[= (b_l + k \times l) \times (f(r) - f(l-1)) - k \times (g(r) - g(l-1)) \]

至此可以 \(O(1)\) 计算极长等差连续段的 \(\sum\limits_{i=l}^r a_i\)

现在问题是知道左端点 \(l\),如何求极长等差连续段的右端点 \(r\)。我们有 \(b_{r-1} - b_r = b_l - b_{l+1}\),即 \(\left\lceil\frac{b_l + (l-r+1)(\left\lceil\frac{b_l}{l+1}\right\rceil-1)}{r}\right\rceil = \left\lceil\frac{b_l}{l+1}\right\rceil\),可以二分得到 \(r\)

总时间复杂度 \(O(TX^{\frac{1}{3}} \log N)\),优化二分上界后可以通过。

code
// Problem: E - Sequence of Multiples
// Contest: AtCoder - AtCoder Regular Contest 135
// URL: https://atcoder.jp/contests/arc135/tasks/arc135_e
// Memory Limit: 1024 MB
// Time Limit: 6000 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 long double ldb;
typedef pair<ll, ll> pii;

const ll mod = 998244353;
const ll inv2 = (mod + 1) / 2, inv6 = 166374059;

ll n, m;

inline ll f(ll x) {
	x %= mod;
	return x * (x + 1) % mod * inv2 % mod;
}

inline ll g(ll x) {
	x %= mod;
	return x * (x + 1) % mod * (x * 2 + 1) % mod * inv6 % mod;
}

inline ll calc(ll l, ll r, ll b, ll k) {
	ll res = (b + k * l % mod) % mod * (f(r) - f(l - 1) + mod) % mod;
	res = (res - k * (g(r) - g(l - 1) + mod) % mod + mod) % mod;
	return res;
}

void solve() {
	scanf("%lld%lld", &n, &m);
	ll p = 1, lst = 0, ans = 0;
	while (p <= n) {
		ll cur = (p == 1 ? m : lst - (lst + p - 1) / p + 1);
		if (p == n) {
			ans = (ans + cur * p % mod) % mod;
			break;
		}
		ll nxt = cur - (cur + p) / (p + 1) + 1;
		ll l = p, r = (cur == nxt ? n - 1 : min(n - 1, p + cur / (cur - nxt))), pos = -1, x = (cur + p) / (p + 1);
		while (l <= r) {
			ll mid = (l + r) >> 1;
			if (x == (cur + (p - mid) * (x - 1) + mid) / (mid + 1)) {
				pos = mid;
				l = mid + 1;
			} else {
				r = mid - 1;
			}
		}
		ans = (ans + calc(p, pos + 1, cur, (cur - nxt + mod) % mod)) % mod;
		lst = cur + (pos + 1 - p) * (nxt - cur);
		p = pos + 2;
	}
	printf("%lld\n", ans);
}

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