CodeForces 1951G Clacking Balls

洛谷传送门

CF 传送门

考虑用相邻两个球之间的距离来描述一个状态。

设距离序列为 \(a_1, a_2, \ldots, a_k\)(忽略 \(0\))。考虑鞅与停时定理,设一个状态的势能为 \(\sum\limits_{i = 1}^k f(a_i)\),一次操作能使得势能期望减少 \(1\)。那么:

\[1 = \frac{1}{n} \sum\limits_{i = 1}^k f(a_i) + f(a_{i \bmod n + 1}) - f(a_i - 1) - f(a_{i \bmod n + 1} + 1) \]

\(g(x) = f(x + 1) - f(x)\),有:

\[n = \sum\limits_{i = 1}^k g(a_i - 1) - g(a_{i \bmod n + 1}) \]

考虑每个数的贡献,有:

\[n = \sum\limits_{i = 1}^k g(a_i - 1) - g(a_i) \]

不难发现令 \(g(x - 1) - g(x) = \frac{n}{m} x\) 满足要求,因为 \(\sum\limits_{i = 1}^k a_i\) 恒等于 \(m\)

若令 \(g(0) = 0\),那么 \(g(x) = -\frac{n}{m} \binom{x + 1}{2}\),因为我们需要在操作后删除 \(a\) 中的 \(0\) 所以必须令 \(f(0) = 0\),那么有 \(f(x) = -\frac{n}{m} \binom{x + 1}{3}\)

终止状态的势能为 \(f(m)\)。于是用初始状态势能减去终止状态势能就是答案。时间复杂度 \(O(n \log n)\)(瓶颈在对每个球的位置排序)。

code
// Problem: G. Clacking Balls
// Contest: Codeforces - Codeforces Global Round 25
// URL: https://codeforces.com/problemset/problem/1951/G
// Memory Limit: 256 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 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 = 300100;
const ll mod = 1000000007;
const ll inv6 = (mod + 5) / 6;

inline ll qpow(ll b, ll p) {
	ll res = 1;
	while (p) {
		if (p & 1) {
			res = res * b % mod;
		}
		b = b * b % mod;
		p >>= 1;
	}
	return res;
}

ll n, m, a[maxn], inv, b[maxn];

inline ll f(ll x) {
	return (mod - n * inv % mod * (x + 1) % mod * x % mod * (x - 1) % mod * inv6 % mod) % mod;
}

void solve() {
	scanf("%lld%lld", &n, &m);
	inv = qpow(m, mod - 2);
	ll ans = (mod - f(m)) % mod;
	for (int i = 1; i <= n; ++i) {
		scanf("%lld", &a[i]);
	}
	sort(a + 1, a + n + 1);
	for (int i = 1; i < n; ++i) {
		b[i] = a[i + 1] - a[i];
	}
	b[n] = a[1] + m - a[n];
	for (int i = 1; i <= n; ++i) {
		ans = (ans + f(b[i])) % mod;
	}
	printf("%lld\n", ans);
}

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

posted @ 2024-04-16 14:02  zltzlt  阅读(12)  评论(0编辑  收藏  举报