一言(ヒトコト)

CF888F Connecting Vertices

这道题我理解了

等我写完代码就来写这个

(脑子是个奇怪的东西,刚才的绿题好像真没听懂,但是这道题我理解了
早知道就先写这道题了


区间DP
\(dp[l,r]\)表示\(l\)\(r\)联通的方案数

观察到我们要连\(n-1\)条边 (也就是一棵树

所以在\([l,r]\)这个区间必定会有一个分割点k
使得\([l,k]\)\([k+1,r]\)都是联通的
但是\([k,k+1]\)是断开的

为什么会这样呢?
因为我们要连n-1条边 (也就是一棵树
如果\([l,k]\)\([k+1,r]\)\([k,k+1]\)都是联通的,这不成了一个环吗

那么我们就知道怎么转移了

\[\sum_{k=l+1}^r dp[l][k]*dp[k+1][r] \]

但这真的对吗

上面这种情况是l与r直接连边的情况,如果不是直接连边呢?

还是和上面类似(也有一个断开的地方(如果没有就成环了
这种情况是\(dp[l][r][1]\),上一种情况就是\(dp[l][r][0]\)

那么就是

\[dp[l][r][0] = \sum_{k=l}^{r-1} (dp[l][k][0] + dp[l][k][1]) * (dp[k+1][r][0] + dp[k+1][r][1]) \]

\[dp[l][r][1] = \sum_{k=l}^{r} dp[l][k][0] * (dp[k][r][0] + dp[k][r][1]) \]

注意判断这个边到底可不可以连,a[i][j]


点击查看代码
#include<bits/stdc++.h>
#define Elysia return
using namespace std;
typedef long long LL;
const int N=510,mod=1e9+7;
int n;
LL a[N][N];
LL f[N][N][2];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>a[i][j];
		}
	}
	for(int i=1;i<=n;i++){
		f[i][i][0]=1;
	}
	for(int len=2;len<=n;len++){
		for(int l=1,r=len;r<=n;l++,r++){
			if(a[l][r]){
				for(int k=l;k<r;k++){
					f[l][r][0]=(f[l][r][0]+(f[l][k][0]+f[l][k][1])*(f[k+1][r][0]+f[k+1][r][1])%mod)%mod;
				}
			}
			for(int k=l+1;k<=r-1;k++){
				if(a[l][k]){
					f[l][r][1]=(f[l][r][1]+f[l][k][0]*(f[k][r][0]+f[k][r][1])%mod)%mod;
				}
					
			}
		}
	}
	cout<<(f[1][n][0]+f[1][n][1])%mod;
	Elysia 0;
}

posted @ 2026-07-30 17:19  冬冬猫  阅读(3)  评论(0)    收藏  举报