[题解]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;
}
posted @ 2026-08-22 10:38  WBIKPS  阅读(1)  评论(0)    收藏  举报