[题解]CF888F Connecting Vertices

思路

注意到当连接 \((i,j)\) 边时,\([i,j]\) 区间中的点无法向区间外的点连边,这有着相当好的“独立性”,考虑区间 dp。

定义 \(dp_{i,j}\) 表示 \([i,j]\) 连成一个连通块时的方案数,考虑转移:

  • \(i,j\) 直接连边,枚举一个断点 \(k\) 表示我们需要将 \([i,k],(k,j]\) 两区间的点分别连成连通块,则有:\(dp_{i,j} \leftarrow \sum_{k = l}^{r - 1}dp_{i,k} \times dp_{k + 1,j}\)
  • \(i,j\) 没有连边,枚举一个断点 \(k\) 表示我们需要连接 \((i,k),(k,j)\) 两条边,则有:\(dp_{i,j} \leftarrow \sum_{k = l}^{r}dp_{l,k} \times dp_{k,r}\)

事实上,这个做法有一些瑕疵。当存在 \(i \to j \to k\) 时,断点分别在 \(j,k\) 时这种情况被计算了两次。对于这类问题,我们通常的套路是只记录第一个为断点/最后一个为断点的贡献,这里我们采用后者。

重新定义 \(dp_{i,j,0/1}\) 表示 \([i,j]\) 连成一个连通块时,\((i,j)\) 没有连边/有连边的方案数,考虑转移:

  • \(dp_{i,j,0} \leftarrow \sum_{k = i}^{j}dp_{i,k,1} \times (dp_{k,j,0} + dp_{k,j,1})\),枚举断点 \(k\) 表示钦定 \(k\)\(i\) 连出去某条链的末端。
  • \(dp_{i,j,1} \leftarrow \sum_{k = i}^{j - 1}(dp_{i,k,0} + dp_{i,k,1}) \times (dp_{k + 1,j,0} + dp_{k + 1,j,1})\),这类情况并不会算重,转移和上面一样。

无法连边的限制显然是好处理的。

Code

#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))

using namespace std;

const int N = 510;
const int mod = 1e9 + 7;
int n;
bool arr[N][N];
int dp[N][N][2];

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++){
        for (re int j = 1;j <= n;j++) arr[i][j] = read();
    }
    for (re int i = 1;i <= n;i++) dp[i][i][0] = 1;
    for (re int len = 2;len <= n;len++){
        for (re int i = 1,j = len;j <= n;i++,j++){
            for (re int k = i + 1;k <= j;k++) chAdd(dp[i][j][0],Mul(dp[i][k][1],Add(dp[k][j][0],dp[k][j][1])));
            if (arr[i][j]){
                for (re int k = i;k < j;k++) chAdd(dp[i][j][1],Mul(Add(dp[i][k][0],dp[i][k][1]),Add(dp[k + 1][j][0],dp[k + 1][j][1])));
            }
        }
    } printf("%lld",Add(dp[1][n][0],dp[1][n][1]));
    return 0;
}
posted @ 2026-01-06 17:20  WBIKPS  阅读(3)  评论(0)    收藏  举报