Description
\(n\)个顶点,\(k\)个点,问有多少三角剖分方案满足任意一个三角内都有偶数个点,\(n \leqslant 6\times 10^2,k\leqslant 2\times 10^4\).
Solution
极角排序+DP.
枚举顶点,然后将点按照与这个点形成向量的极角排序,这样可以和其他点形成的三角形是否合法,也就是这一部分一定要有偶数个点才行.
然后就是三角剖分的DP了,\(f[i][j]\) 表示\(i,j\)之间的顶点有多少种剖分方案,然后划分成两部分,来做,记搜会好写些.
复杂度\(O(nklogk+n^3)\)
Code
/**************************************************************
Problem: 2087
User: BeiYu
Language: C++
Result: Accepted
Time:7936 ms
Memory:4756 kb
****************************************************************/
#include <bits/stdc++.h>
using namespace std;
#define mpr make_pair
#define x first
#define y second
typedef pair< int,int > pr;
const int N = 650;
const int M = 2e4+50;
pr operator - (const pr &a,const pr &b) { return mpr(a.x-b.x,a.y-b.y); }
int operator * (const pr &a,const pr &b) { return a.x*b.y-a.y*b.x; }
inline int in(int x=0,char ch=getchar(),int v=1) {
while(ch>'9' || ch<'0') v=(ch=='-'?-1:v),ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return x*v; }
int n,k,m;
pr B,r[N],p[M];
int f[N][N],g[N][N];
void out(pr a) { cout<<a.x<<" "<<a.y<<endl; }
int cmp(const pr &a,const pr &b) { return (a-B)*(b-B)<0; }
int DFS(int l,int r) {
if(l==r || l+1==r) return f[l][r]=1;
if(~f[l][r]) return f[l][r];
f[l][r]=0;
for(int i=l+1;i<r;i++) f[l][r]=(f[l][r]+DFS(l,i)*DFS(i,r)*g[l][i]*g[i][r]%m)%m;
return f[l][r];
}
int main() {
// freopen("in.in","r",stdin);
n=in(),k=in(),m=in();
for(int i=1;i<=n;i++) {
int x=in(),y=in();
r[i]=mpr(x,y);
}
for(int i=1;i<=k;i++) {
int x=in(),y=in();
p[i]=mpr(x,y);
}
for(int i=1;i<=n;i++) {
B=r[i];
sort(p+1,p+k+1,cmp);
int s=1;
for(int j=i+1;j<=n;j++) {
while(s<=k && (r[j]-B)*(p[s]-B)>0) s++;
g[i][j]=(s&1)&&((p[s]-B)*(r[j]-B)!=0);
}
}
/* for(int i=1;i<=n;i++) {
for(int j=i+1;j<=n;j++) {
cout<<g[i][j]<<" ";
}cout<<endl;
}*/
memset(f,0xff,sizeof(f));
cout<<DFS(1,n)<<endl;
/* for(int i=1;i<=n;i++) {
for(int j=i+1;j<=n;j++) {
cout<<f[i][j]<<" ";
}cout<<endl;
}*/
return 0;
}
/*
5 4 10
5 5
3 0
-1 -1
-3 4
1 10
1 0
-1 0
1 6
-2 5
*/