「AGC028D」Chords 题解

题目简介

给定一个圆, 圆上均等地放着 \(2N\) 个点, 已有 \(K\) 对点之间连好了线段, 从中选择剩下 \(N−K\) 对点随意连线段(每个点只连一条线段)。

两点联通当且仅当两点在同一条线段上或两点所属于的线段相交, 求所有连边方案中, 联通块的个数和。

分析

将圆从 \(1\)\(2N\) 线性展开,发现规律:倘若弦 \(AB\)\(CD\) 相交,当且仅当数轴上的线段 \(AB\)\(CD\) 相交且不包含。

经过观察(读者可以画一画图),不难发现,一个连通块在数轴上一定对应了一个区间,满足该连通块完全在这个区间内,而且区间端点属于连通块(否则有点连到连通块外面,一定会与连通块内部的弦有交,连通块会变大)。但是要注意这个区间内并非全都是这个连通块,可能其中还有小连通块。

\(p[x]\) 为题目中已连边的点 \(x\) 的对应点。

又记\(f[l][r]\) 为区间 \([l,r]\) 为一个连通块,且 \(l,r\) 属于这个连通块的方案数。根据上述,我们可以发现,\(f[l][r]\) 有意义的前提是\(\forall x\in[l,r],\ p[x] \in [l,r]\)

\(g[i]\) 表示 \(i\) 个点随意连的方案数, \(h(l,r)\) 表示 \([l,r]\) 内没有被钦定的点数。

打表找规律:

\[g(x)=\left\{ \begin{aligned}&0&&,x =2k+1,k\in \Z \\ &g(x-2)\times(x-1)&&,x=2k,k\in\Z\end{aligned}\right. \]

所以说,如果没有“ \(l,r\) 属于同一个连通块 ”的限制的话,那么 \(f[l][r]=g[h(l,r)]\)

现在需要除掉 \(l\) 的右端点不是 \(r\) 的情况,可以枚举 \(r\) 的右端点 \(i\) ,减去以 \(i\) 为右端点的贡献,及 \(f[l][i]\times g[h(i+1,r)]\)

总的来说:

\[f[l][r]=g[h(l,r)]-\prod^{r-1}_{i=l+1}f[l][i]\times g[h(i+1,r)] \]

最后,统计答案,即统计连通块的贡献之和:

\[\mbox{Ans} =\sum f[l][r]\times g[h(1,l-1)+h(r+1,2n)] \]

\(AC\ Code\)

#include<cstdio>
#include<iostream>
using namespace std;
const int Mod=1e9+7;
int f[605][605];
int g[605],p[605],c[605];
int ans;
inline int h(int l,int r){return c[r]-c[l-1];}
void solve(int l,int r,int n){
	for(int i=l;i<=r;++i)
		if(p[i]&&p[i]<l||p[i]>r)return ;
	f[l][r]=g[h(l,r)];
    for(int i=l+1;i<r;++i)
        f[l][r]=(f[l][r]-1ll*f[l][i]*g[h(i+1,r)]%Mod+Mod)%Mod;
    ans+=1ll*f[l][r]*g[h(1,l-1)+h(r+1,n)]%Mod;
    ans%=Mod;
}
int main(){
	int n,m;cin>>n>>m;
	n<<=1;g[0]=1;
	for(int i=2;i<=n;i+=2)g[i]=1ll*g[i-2]*(i-1)%Mod;
	for(int i=1;i<=m;++i){
		int x,y;cin>>x>>y;
		p[x]=y,p[y]=x;
	}
	for(int i=1;i<=n;++i)c[i]=c[i-1]+(!p[i]);
	for(int i=1;i<=n;++i)
		for(int j=i+1;j<=n;j+=2)solve(i,j,n);
	cout<<ans<<'\n';
	return 0;
}

$$-----EOF-----$$

posted @ 2022-07-11 14:01  AlienCollapsar  阅读(57)  评论(0编辑  收藏  举报
// 生成目录索引列表 // ref: http://www.cnblogs.com/wangqiguo/p/4355032.html // modified by: zzq