【学习笔记】[AGC039E] Pairing Points

太复杂了,做不动。

设第 2 n 2n 2n个点与 k k k相连,这样把点分成了左右两个集合,一定存在左边的 x x x与右边的 y y y相连的一条边,并且这个结构有一个比较优美的性质,左右相连的边的点的编号应该是单调,否则会存在环。那么我们取最靠近上端的那条边。

那么我们用 [ i : j ] ( k ) [i:j](k) [i:j](k)表示 [ i : j ] [i:j] [i:j]这一段圆弧, k k k向圆弧外的一个点连了边的方案数。如果我们直接将问题拆分成 [ i : k − 1 ] ( x ) [i:k-1](x) [i:k1](x) [ k + 1 : j ] ( y ) [k+1:j](y) [k+1:j](y)那么显然这样的方案是合法的,因为任意一条边都能和 ( x , y ) (x,y) (x,y)互达并且不存在环。显然我们只遗漏了 x x x下端点和 y y y下端点连边的情况,而我们事实上可以选择一条割线,使得将 ( ? , k ) (?,k) (?,k)删去后变成不连通的两部分,更形象的讲,删去 ( ? , k ) (?,k) (?,k)后与 ( x , y ) (x,y) (x,y)联通的一定是上端两段圆弧,那么枚举 p p p, q q q,显然 p p p, q q q上端只存在 ( x , y ) (x,y) (x,y)一条横边,那么可以拆分成 [ i : p ] ( x ) [i:p](x) [i:p](x) [ q : j ] ( y ) [q:j](y) [q:j](y),下端圆弧因为不存在向上的边因此直接拆成 [ p + 1 : q − 1 ] ( k ) [p+1:q-1](k) [p+1:q1](k)

复杂度 O ( n 7 ) O(n^7) O(n7)。据说常数极小。

#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define db long double
#define cpx complex<db>
using namespace std;
int n;
char a[45][45];
ll dp[45][45][45],res;
ll dfs(int i,int j,int k){
	if(k<i||k>j)return 0;
	if(i==j)return 1;
	if(i==k||j==k)return 0;
	if(~dp[i][j][k])return dp[i][j][k];
	ll res(0);
	for(int x=i;x<k;x++){
		for(int y=k+1;y<=j;y++){
			if(a[x][y]=='1'){
				for(int p=x;p<k;p++){
					for(int q=k+1;q<=y;q++){
						res+=dfs(i,p,x)*dfs(q,j,y)*dfs(p+1,q-1,k);
					}
				}
			}
		}
	}
	return dp[i][j][k]=res;
}
int main(){
	memset(dp,-1,sizeof dp);
	scanf("%d",&n),n<<=1;
	for(int i=1;i<=n;i++){
		scanf("%s",a[i]+1);
	}for(int i=1;i<n;i++)if(a[n][i]=='1')res+=dfs(1,n-1,i);
	printf("%lld",res);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值