[dp记录]ARC117E Zero-Sum Ranges 2
贴个官方题解的图:

对于一个序列,对其做前缀和,则对数为 \(\sum\limits_{i=-n}^n \dbinom {cnt(i)} 2\)。
从下往上一层一层决策,记 \(dp(i,j,c)\) 为占用了 \(i\) 个位置,分成了 \(j\) 段,对数为 \(c\) 的方案数,枚举上一层放 \(x\) 个数,则有转移:
\[\dbinom{x - 1}{j}dp(i,j,c) \longrightarrow dp(i+x,x-j,c+\binom x 2)
\]
手玩一下便可知道段数为 \(x-j\)。
考虑怎么计算答案,由于 \(1,-1\) 的数量是相等的,我们可以确定 \(s_0 = s_{2n} = 0\),也就是说,最终的前缀和 \(s\) 的图像大概长这样:

枚举 \(\ge 0\) 的段数 \(j\) 即可确定 \(\le 0\) 的段数必须为 \(j - 1\) 段(将 \(j\) 段连接在一起)。
于是有:
\[ans = \sum\limits_{i=2}^{2*n+1}\sum\limits_{j=1}^{n+1}\sum\limits_{c=0}^{k}dp(i,j,c)dp(2*n+1-i,j-1,k-c)
\]
时间复杂度 \(\mathrm{O(n^5)}\) 。
\(\texttt{Code:}\)
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
inline void read(int &x) {
x = 0; int f = 0; char c = getchar();
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
x = f ? -x : x;
}
const int cmd = 998244353;
const int N = 35;
int fpow(int a, int b) {
int res = 1;
for (; b; b >>= 1, a = 1ll * a * a % cmd)
if (b & 1) res = 1ll * res * a % cmd;
return res;
}
int add(int a, int b) {a += b; return a < cmd ? a : a - cmd;}
int sub(int a, int b) {a -= b; return a < 0 ? a + cmd : a;}
int n, k;
ll dp[N << 1][N][N * N], binom[N << 1][N << 1];
int main() {
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
read(n); read(k);
for (int i = 0; i <= 2 * n; i++) {
binom[i][0] = 1;
for (int j = 1; j <= i; j++)
binom[i][j] = binom[i - 1][j] + binom[i - 1][j - 1];
}
for (int i = 0; i <= n + 1; i++)
if (i * (i - 1) / 2 <= k) dp[i][i][i * (i - 1) / 2] = 1;
for (int i = 0; i <= 2 * n + 1; i++)
for (int j = 1; j <= min(i, n + 1); j++)
for (int c = 0; c <= k; c++)
if (dp[i][j][c]) {
for (int x = j + 1; x <= n * 2 + 1 - i; x++)
if (c + x * (x - 1) / 2 <= k && x - j <= n + 1)
dp[i + x][x - j][c + x * (x - 1) / 2] += dp[i][j][c] * binom[x - 1][j];
}
ll ans = 0;
for (int i = 2; i <= 2 * n + 1; i++)
for (int j = 1; j <= n + 1; j++)
for (int c = 0; c <= k; c++)
ans += dp[i][j][c] * dp[n * 2 + 1 - i][j - 1][k - c];
printf("%lld", ans);
return 0;
}

浙公网安备 33010602011771号