LG5369 [PKUSC2018] 最大前缀和
Problem
Analysis
正解思路
题目强调了最大前缀和,那么我就应该思考最大前缀和的性质:
设当前序列为 \(a\),设前 \(i\) 个为最大前缀。
- 不存在 \(1< j\le i\) 使得 \(\sum_{k=j}^{i}a_k<0\),否则可以直接舍去。(注意这里的最大前缀和必须选择数,所以 \(j\) 不能从 \(1\) 开始)
- 不存在 \(i< j\le n\) 使得 \(\sum_{k=i+1}^{j}a_k\ge 0\),否则可以直接加上。
其实我们也就发现这是前 \(i\) 个取到最大前缀和的充要条件。 (对于性质的刻画最终都需要回到这一步)
再根据 \(n\le 20\) 很小,我们就容易想到状压 dp 解决,这样就首先明确了计算方法。
考虑解决问题,答案其实是解与方案数的乘积。解是很好计算的,枚举子集统计和就行,记为 \(sum_i\)。考虑方案数的计算,发现这两个性质条件互不冲突,那么可以分别计算它们的方案数,再相乘就得出答案。
令 \(U\) 为全集,设 \(f_i\) 为集合 \(i\) 组成的排列最大前缀和 \(=sum_i\) 的方案数,\(g_i\) 为集合 \(i\) 组成的排列最大前缀和 \(<0\) 的方案数。分别对应条件 \(1\) 和 \(2\)。
考虑转移,\(g\) 的转移很直接,若 \(sum_i\ge 0\),\(g_i=0\),否则,枚举当前加入的数放在最后一位,\(g_i=\sum_{j\in i}g_{i-j}\)。\(f\) 的转移由于无法确定最终序列最大前缀和(总和)是否 \(\ge 0\),所以只能往后刷表,若 \(sum_i\ge 0\),\(f_{i+j}=\sum_{j\notin i}f_i\)。
错因总结
我花费了很多时间从排列的性质考虑问题,这确实是一个方向,但没有尝试思考最大前缀和的性质是一个很严重的思维局限问题。
AC Code
点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define i128 __int128
#define fi first
#define se second
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define mk make_pair
#define INF 0x3f3f3f3f
#define INFx 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 21, M = 1 << N;
const int mod = 998244353;
int n;
int a[N];
int s[M], f[M], g[M];
void add(int &x, int y) {
x += y;
if (x >= mod) x -= mod;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
for (int i = 0; i < (1 << n); i ++) {
for (int j = 1; j <= n; j ++) {
if (i >> j - 1 & 1) add(s[i], a[j]);
}
}
for (int i = 1; i <= n; i ++) f[1 << i - 1] = 1; // 注意单个元素也算
g[0] = 1;
for (int i = 1; i < (1 << n); i ++) {
if (s[i] >= 0) {
for (int j = 1; j <= n; j ++) {
if (!(i >> j - 1 & 1)) add(f[i ^ (1 << j - 1)], f[i]);
}
}
else {
for (int j = 1; j <= n; j ++) {
if (i >> j - 1 & 1) add(g[i], g[i ^ (1 << j - 1)]);
}
}
}
int ans = 0, tot = (1 << n) - 1;
for (int i = 0; i < (1 << n); i ++) {
s[i] = (s[i] + mod) % mod;
add(ans, 1ll * s[i] * f[i] % mod * g[tot ^ i] % mod);
}
cout << ans << '\n';
return 0;
}

浙公网安备 33010602011771号