[题解]P17284 「IXOI R2」想不出来
我们要对 \(p'\) 权值求和,那需要我们从 \(p'\) 的一些性质入手:
- \(\sum_{i = 1}^{n} p'_i = n\)。这个性质非常显然,应该是读完题就能发现的。
- 若存在 \(p'_i > 1\),则 \(p'_{i - 1} = p'_{i + 1} = 0\)(将 \(p'_0\) 和 \(p'_{n + 1}\) 视作 \(0\))。因为 \(p'_i > 0\) 所以必定在最后一次操作 \(i - 1\) 和 \(i + 1\) 之后,至少操作了一次 \(i\),那么 \(p'_{i - 1}\) 和 \(p'_{i + 1}\) 必定被归零了。
由于 \(\sum p'\) 的量级比较小,考虑从后往前钦定 \(p'\),定义 \(dp_{i,j}\) 表示把 \(j\) 个“1”丢到前 \(i\) 个位置的方案数,答案显然为 \(dp_{n,n}\)。
- \(p'_i = 0\):\(dp_{i,j} \leftarrow dp_{i - 1,j}\)。
- \(p'_i > 1\):由性质二,\(p'_{i - 1} = 0\),则 \(dp_{i,j} \leftarrow \sum_{k = 2}^{j}x_i^{k}dp_{i - 2,j - k}\)。
- \(p'_i = 1\):
- \(p'_{i - 1} = 0\):与 \(p'_i > 1\) 的情况相同,即 \(dp_{i,j} \leftarrow x_idp_{i - 2,j - 1}\)。
- \(p'_{i - 1} = 1\):注意到此时不可能有 \(i + 1 \sim n\) 的位置的值通过操作移到 \(1 \sim i\) 中,所以这种情况一定只出现于 \(i = j\) 的时候。同时注意到由于 \(p'_{i - 1} = 1\),\(p'_{i - 2}\) 只能是 \(0\) 或 \(1\),这时候转移使用 \(dp\) 显然是有问题的,不妨令 \(f_i\) 表示长度为 \(i\) 的 \(p\) 序列通过操作能得到所有 \(p'_i = 0/1\) 的 \(p'\) 的权值和。则 \(dp_{i,j} \leftarrow x_{i - 1}x_{i}f_{i - 2}\)。
- 综上,\(dp_{i,j} \leftarrow dp_{i - 1,j} + \sum_{k = 1}^jx_i^kdp_{i - 2,j - k} + [i = j]x_{i - 1}f_{i - 2}\)。
考虑 \(f\) 的转移:
- \(p'_i = 0\):\(f_i \leftarrow dp_{i - 1,i}\)。
- \(p'_i = 1\):
- \(p'_{i - 1} = 0\):此时对 \(p'_{i - 2}\) 没有特殊限制,则 \(f_i \leftarrow x_idp_{i - 2,i - 1}\)。
- \(p'_{i - 1} = 1\):此时 \(p'_{i - 2}\) 依旧只能是 \(0/1\),则 \(f_i \leftarrow x_{i - 1}x_{i}f_{i - 1}\)。
- 综上,\(f_i \leftarrow dp_{i - 1,i} + x_idp_{i - 2,i - 1} + x_{i - 1}x_if_{i - 2}\)。
\(dp\) 转移复杂度 \(\Theta(n^3)\),\(f\) 转移复杂度 \(\Theta(n^2)\)。令 \(S_{i,j} = \sum_{k = 1}^jx_i^kdp_{i - 2,j - k}\),容易发现 \(S_{i,j} = x_i(S_{i,j - 1} + dp_{i - 2,j - 1})\),把 \(S_{i,j}\) 代入 \(dp\),此时复杂度 \(\Theta(n^2)\)。
#include <bits/stdc++.h>
#define re register
#define int long long
#define Add(a,b) (((a) + (b)) % mod)
#define Mul(a,b) ((a) * (b) % mod)
#define chAdd(a,b) (a = Add(a,b))
#define chMul(a,b) (a = Mul(a,b))
using namespace std;
const int N = 8010;
const int mod = 1e9 + 7;
int n,a[N];
int f[N],dp[N][N];
inline int read(){
int r = 0,w = 1;
char c = getchar();
while (c < '0' || c > '9'){
if (c == '-') w = -1;
c = getchar();
}
while (c >= '0' && c <= '9'){
r = (r << 3) + (r << 1) + (c ^ 48);
c = getchar();
}
return r * w;
}
signed main(){
n = read();
for (re int i = 1;i <= n;i++) a[i] = read();
f[0] = dp[0][0] = dp[1][0] = 1,f[1] = a[1];
for (re int i = 1;i <= n;i++) dp[1][i] = Mul(dp[1][i - 1],a[1]);
for (re int i = 2;i <= n;i++){
for (re int j = 0,sum = 0;j <= n;j++){
dp[i][j] = dp[i - 1][j];
if (i == j) chAdd(dp[i][j],Mul(Mul(a[i - 1],a[i]),f[i - 2]));
if (j) chAdd(sum,dp[i - 2][j - 1]);
chAdd(dp[i][j],chMul(sum,a[i]));
} f[i] = Add(dp[i - 1][i],Add(Mul(a[i],dp[i - 2][i - 1]),Mul(Mul(a[i - 1],a[i]),f[i - 2])));
} printf("%lld",dp[n][n]);
return 0;
}

浙公网安备 33010602011771号