原題傳送門
這種題目真有意思,總是披着期望的外套,然後還不忘說一聲答案乘一個xxx,可以證明是整數
這不就是方案和嗎,這樣子又不是會有人看不出來
求全排列的最大前綴和之和
首先可以發現一個重要性質,對於一個排列,若最大前綴和的結尾位置在,可以發現
根據這個性質可以狀壓dp
令
表示狀態的所有數之和
表示狀態的排列最大前綴和爲的方案數
表示狀態的排列所有前綴和都<=0的方案數
可以得到答案
通過dp得到
Code:
#include <bits/stdc++.h>
#define maxn 1200010
#define LL long long
using namespace std;
const LL qy = 998244353;
int n, N, power[25], num[maxn];
LL g[maxn], f[maxn], sum[maxn], ans;
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
int lowbit(int x){ return x & -x; }
void upd(LL &x, LL y){ if ((x += y) >= qy) x -= qy; }
int main(){
n = read(), N = (1 << n) - 1;
power[0] = 1;
for (int i = 1; i <= 20; ++i) power[i] = power[i - 1] << 1;
for (int i = 1; i <= n; ++i) num[power[i - 1]] = read();
for (int i = 1; i <= N; ++i) upd(sum[i], sum[i ^ lowbit(i)] + num[lowbit(i)]);
g[0] = 1;
for (int i = 0; i <= N; ++i)
if (sum[i] <= 0)
for (int j = 0; j < n; ++j)
if (i & power[j]) upd(g[i], g[i ^ power[j]]);
for (int i = 0; i < n; ++i) f[power[i]] = 1;
for (int i = 0; i <= N; ++i){
upd(ans, (sum[i] + qy) % qy * f[i] % qy * g[N ^ i] % qy);
if (sum[i] > 0)
for (int j = 0; j < n; ++j)
if (!(i & power[j])) upd(f[i ^ power[j]], f[i]);
}
printf("%lld\n", ans);
return 0;
}