題面
題解
這題有一定思維難度 ... (我就沒想出來 , 靠大佬口胡的)
不難發現 , 成為最大前綴和位置 \(p\) 后面的所有前綴都不能 \(> 0\) .
如果可以 \(>0\) 那么后面必存在一點可以替換當前的答案 .
有了這個思路 , 那我們可以把每個序列拆成兩端考慮 , 而分割點就是位置 \(p\) .
首先令 \(sum_i\) 為 \(i\) 這個狀態所有點的代數和 , 便於轉移 .
-
令 \(f_{i}\) 為 \(i\) 這個狀態 滿足 集合的最大前綴和 等於 集合和 \(sum_i\) 的方案數 .
這個轉移的話 , 我們考慮倒着插入數字 , 如果存在后綴這個 \(sum_{suf} >0\) 那么可以直接轉移了 .
因為這樣構造 , 新得到的序列肯定比當前的更加優秀 . 轉移方程就是
\[\displaystyle k \notin i ~\mathrm{and}~ sum_i > 0 : f_i \to f_{i+k} \] -
令 \(g_i\) 為 \(i\) 這個狀態 滿足 所有前綴和 都 \(\le 0\) 的方案數 .
這個容易轉移一些 , 從前往后插入 , 每次填入的集合和都需要 \(\le 0\) 就行了.
\[k \notin i ~\mathrm{and}~ sum_{i+k} \le 0 : g_i \to g_{i+k} \]
有了這個答案就是 \(\sum sum_{i} \times f_i \times g_{\mathrm{maxsta}-i}\) .
總時間復雜度就是 \(O(n \times 2^n)\) 然后我用 \(O(2^n)\) 求的 \(sum\) 數組 , 卡進了rank1 ...qwq
代碼
#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
using namespace std;
inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}
inline int read() {
int x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
return x * fh;
}
void File() {
#ifdef zjp_shadow
freopen ("6433.in", "r", stdin);
freopen ("6433.out", "w", stdout);
#endif
}
const int N = 21, inf = 0x7f7f7f7f, Mod = 998244353;
int n, a[N], sum[1 << N], f[1 << N], g[1 << N], num[1 << N];
#define lowbit(x) (x & -x)
#define Add(a, b) if (((a) += (b)) >= Mod) (a) -= Mod
int main () {
File();
n = read();
For (i, 0, n - 1) num[1 << i] = a[i] = read();
int maxsta = (1 << n) - 1;
For (i, 0, maxsta)
sum[i] = sum[i ^ lowbit(i)] + num[lowbit(i)];
g[0] = 1;
For (i, 0, maxsta) if (sum[i] <= 0)
For (j, 0, n - 1) if ((i >> j) & 1)
Add(g[i], g[i ^ (1 << j)]);
For (i, 0, n - 1) f[1 << i] = 1;
int ans = 0;
For (i, 0, maxsta) {
if (sum[i] > 0)
For (j, 0, n - 1) if (!((i >> j) & 1))
Add(f[i | (1 << j)], f[i]);
Add(ans, (1ll * (sum[i] + Mod) * f[i] % Mod * g[maxsta ^ i] % Mod));
}
printf ("%d\n", ans);
return 0;
}