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;
}

浙公网安备 33010602011771号