题解 T378016 【Polygon】
Polygon
给定一个凸多边形的三角剖分,求生成树的个数。
观察到
计数问题考虑
- 对于任意一条在凸多边形上的边,都能找到另一个点与这条边构成一个三角形。
我们可以随便找一条边,不妨令这条边为
相似的结构出现了,我们可以用分治来维护这个
在
接下来考虑合并答案,以
还有一个问题就是如何找三角形,我的做法是按照顺/逆时针枚举每一个点的所有边,两条相邻的边一定构成一个三角形,可以使用 unordered_map 进行存储,并且可以通过点的顺序来区分包含该条边的至多两个三角形,具体看代码实现。
时间复杂度为
Code:
#include<bits/stdc++.h>
typedef long long ll;
typedef long double ld;
using namespace std;
const int N=200010,M=2000010,p=998244353;
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x<y?x:y;}
inline void swap(int &x,int &y){x^=y^=x^=y;}
int n,top=1;
ll f[N<<2][2];
vector<int> v[N];
unordered_map<int,int> w[N];
void add(int x,int y){
if(x>y)swap(x,y);
v[x].push_back(y);
v[y].push_back(x+N);
w[x][y]=w[y][x]=N;
}
void solve(int x,int lst,int l,int r){
if(l+1==r){
f[x][0]=0,f[x][1]=1;
return;
}
int u=w[l][r];
if(u==lst||u==N)u=w[r][l];
int ls=++top,rs=++top;
solve(ls,r,l,u);
solve(rs,l,u,r);
f[x][1]=(f[x][1]+f[ls][1]*f[rs][1]%p)%p;
f[x][1]=(f[x][1]+f[ls][1]*f[rs][1]%p)%p;
f[x][1]=(f[x][1]+f[ls][0]*f[rs][1]%p)%p;
f[x][1]=(f[x][1]+f[ls][1]*f[rs][0]%p)%p;
f[x][0]=(f[x][0]+f[ls][1]*f[rs][1]%p)%p;
f[x][0]=(f[x][0]+f[ls][1]*f[rs][0]%p)%p;
f[x][0]=(f[x][0]+f[ls][0]*f[rs][1]%p)%p;
f[x][0]=(f[x][0]+f[ls][0]*f[rs][0]%p)%p;
}
int main(){
scanf("%d",&n);
for(int i=1;i<n;i++)
add(i,i+1);
add(1,n);
for(int i=1;i<=n-3;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=1;i<=n;i++){
sort(v[i].begin(),v[i].end());
for(int j=0;j<(int)v[i].size();j++)
if(v[i][j]>N)v[i][j]-=N;
}
for(int i=1;i<=n;i++){
for(int j=1;j<(int)v[i].size();j++){
int x=v[i][j-1],y=v[i][j];
w[x][y]=i;
}
}
solve(1,0,1,n);
printf("%lld\n",(f[1][0]+f[1][1])%p);
return 0;
}