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
*/