[CCPC 2024 重庆站] Median Replacement 题解
题意
给定一个长为 \(n\) 的整数序列 \(a_1,a_2,\dots,a_n\),你需要对 \(a\) 进行若干次如下操作,使得 \(a\) 中所有数均相等:
- 选择一段长为大于 \(1\) 的奇数的区间 \(a_l,a_{l+1},\ldots,a_r\),并将此区间内的所有数均替换为它们的中位数。
设最终 \(a_1=a_2=\ldots=a_n=x\),我们定义序列 \(a\) 的值为 \(x\) 的最大值。
请你求出所有满足 \(\forall\ 1\le i\le n\),\(l_i\le a_i\le r_i\) 的整数序列 \(a\) 的值之和。
由于答案可能很大,请对 \(10^9+7\) 取模。
思路
不难发现,答案 \(\text{ans} = \sum x \times \operatorname{cnt}[i=x]\) ,其中 \(\operatorname{cnt}[i=x]\) 为整个区间被覆盖成 \(x\) 的方案数。
进而可以转化成 \(\text{ans} = \sum \operatorname{cnt}[i\geq x]\) ,其中 \(\operatorname{cnt}[i\geq x]\) 为整个区间被覆盖成大于等于 \(x\) 的方案数。
我们继续考虑什么样子的情况是合法的。
如果存在连续三个数,其中两个数大于等于 \(x\),那么整个序列能被全部被变成大于等于 \(x\) 的数 ,也就是:
我们构造考虑新的数列 \(b\)
那么合法情况可以转化为:
但是我们发现求 \(\operatorname{cnt}[i\geq x]\) 并不好求,但是我们发现求总方案数减去\(\operatorname{cnt}[i < x]\) 是好求的。
那我们枚举阈值\(x\), 设 \(dp_{i,0/1,0/1}\) 为前 \(i\) 个数中最后两位在 \(b\) 中的值分别为 \(0/1,0/1\)的方案数,显然有转移:
其中
复杂度\(\Theta(n \times V)\) ,\(V\) 为值域。
我们接着考虑如何优化。
我们注意到 \(x\) 的取值在一段\([L,R]\) 中时,方案数一定是一个常数或者一个一次函数。
有
以及
因此,将所有 \(1,\quad 10^9+1,\quad l_i,\quad r_i+1\) 排序去重,相邻两个端点构成一个整数区间
每一段的贡献即为
其中
对于 \(S_k(t)=\sum_{u=1}^t u^k\) 使用拉格朗日插值即可
Code:
\(\text{C++ Code:}\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int MAXN = 200 + 5;
constexpr int MOD = 1e9 + 7;
int n;
int l[MAXN], r[MAXN];
int frac[MAXN], ifrac[MAXN];
int inv[MAXN];
int y[MAXN][MAXN];
void Mod(int& x) {
if (x >= MOD) x -= MOD;
if (x < 0) x += MOD;
}
struct Poly: vector<int> {
Poly(int sz, int val = 0) : vector<int>(sz, val) {}
Poly(vector<int> c = {}) : vector<int>(c) {}
Poly operator + (const Poly& b) const {
Poly res(max(size(), b.size()));
for (int i = 0; i < (int)size(); ++i) Mod(res[i] += (*this)[i]);
for (int i = 0; i < (int)b.size(); ++i) Mod(res[i] += b[i]);
return res;
}
Poly operator * (const Poly& b) const {
Poly res(size() + b.size() - 1);
for (int i = 0; i < (int)size(); ++i)
for (int j = 0; j < (int)b.size(); ++j)
Mod(res[i + j] += (*this)[i] * b[j] % MOD);
return res;
}
};
Poly dp[MAXN][4];
int qpow(int base, int x) {
int res = 1;
while(x) {
if (x & 1)
res = res * base % MOD;
base = base * base % MOD, x >>= 1;
}
return res;
}
void init() {
frac[0] = 1;
for (int i = 1; i < MAXN; ++i)
frac[i] = frac[i - 1] * i % MOD;
ifrac[MAXN - 1] = qpow(frac[MAXN - 1], MOD - 2);
for (int i = MAXN - 2; i >= 0;--i)
ifrac[i] = ifrac[i + 1] * (i + 1) % MOD;
for (int i = 1; i < MAXN; ++i)
y[i][0] = 1;
for (int i = 0; i < MAXN; ++i)
for (int j = 1; j < MAXN; ++j)
y[i][j] = (y[i][j - 1] + qpow(j, i)) % MOD;
}
Poly calc(int l, int r, int L, int R, int c) {
Poly res(2);
if (c) {
if (l <= L && R <= r) res[0] = r + 1, res[1] = -1;
if (R < l) res[0] = r - l + 1, res[1] = 0;
if (r < L) res[0] = 0, res[1] = 0;
}
else {
if (l <= L && R <= r) res[0] = -l, res[1] = 1;
else if (r < L) res[0] = r - l + 1, res[1] = 0;
else if (R < l) res[0] = 0, res[1] = 0;
}
return res;
}
int calc_power_sum(int x, int k) {
if (x <= n + 2)
return y[k][x];
int mul = 1;
for (int i = 1; i <= n + 2; ++i)
(mul *= (x - i)) %= MOD;
int res = 0;
for (int i = 1; i <= n + 2; ++i) {
int tmp = y[k][i] * mul % MOD * qpow(x - i , MOD - 2) % MOD * ifrac[i - 1] % MOD * ifrac[n + 2 - i] % MOD;
(((res += qpow(-1, (n + 2 - i) & 1) * tmp) %= MOD) += MOD) %= MOD;
}
return res;
}
void solve() {
cin >> n;
vector<int> vec;
vec.reserve(2 * n + 2);
vec.push_back(1), vec.push_back(1e9 + 1);
for (int i = 1; i <= n; ++i)
cin >> l[i], vec.push_back(l[i]);
for (int i = 1; i <= n; ++i)
cin >> r[i], vec.push_back(r[i] + 1);
sort(vec.begin(), vec.end());
vec.erase(unique(vec.begin(), vec.end()), vec.end());
int tot = 1;
for (int i = 1; i <= n; ++i)
(tot *= (r[i] - l[i] + 1)) %= MOD;
int res = 0;
for (int i = 0; i + 1 < (int)vec.size(); ++i) {
int L = vec[i], R = vec[i + 1] - 1;
dp[2][0] = calc(l[1], r[1], L, R, 0) * calc(l[2], r[2], L, R, 0);
dp[2][1] = calc(l[1], r[1], L, R, 1) * calc(l[2], r[2], L, R, 0);
dp[2][2] = calc(l[1], r[1], L, R, 0) * calc(l[2], r[2], L, R, 1);
for (int j = 3; j <= n; ++j) {
dp[j][0] = (dp[j - 1][0] + dp[j - 1][1]) * calc(l[j], r[j], L, R, 0);
dp[j][1] = dp[j - 1][2] * calc(l[j], r[j], L, R, 0);
dp[j][2] = dp[j - 1][0] * calc(l[j], r[j], L, R, 1);
}
auto F = dp[n][0] + dp[n][1] + dp[n][2];
int ans = tot * (R - L + 1) % MOD;
for (int i = 0; i < (int)F.size(); ++i) {
ans -= F[i] * (calc_power_sum(R, i) - calc_power_sum(L - 1, i) + MOD) % MOD;
(ans += MOD) %= MOD;
}
(res += ans) %= MOD;
}
cout << res<< '\n';
}
signed main() {
#ifndef DEBUG
ios::sync_with_stdio(0), cin.tie(0);
freopen("game.in", "r", stdin);
freopen("game.out", "w", stdout);
#else
#endif
init();
int T;
cin >> T;
while (T--)
solve();
return 0;
}

浙公网安备 33010602011771号