BZOJ2087[Poi2010] Sheep
Description
Lyx的QQ牧場養了很多偶數個的羊,他是Vip,所以牧場是凸多邊形(畸形)。現在因爲他開掛,受到了懲罰,系統要求他把牧場全部分爲三角形(劃分線不能在牧場中相交,只能在頂點相交),羊也是有個性的,如果他們在三角形中是單數就會有羊自殺(Lyx的樣就是畸形),這讓Lyx很難辦,於是他向你求助了。
Input
輸入:第一行由空格隔開的3個整數n(4<=n<=600),k(2<=k<=20000),m(2<=m<=20000),n表示牧場的頂點數,k表示羊的個數(保證爲偶數)。接下來n行爲頂點的座標xi、yi,(-15000<=xi,yi<=15000)由空格隔開,接下來k行爲羊的座標,pi,pj,和xi,yi範圍一樣但是不會在頂點上,嚴格在牧場內。
Output
輸出:牧場能劃分的總方案數被m除的餘數。
Sample Input
5 4 10
5 5
3 0
-1 -1
-3 4
1 10
1 0
-1 0
1 6
-2 5
Sample Output
3
Solution:
比較明顯是dp吧。其實之前TC上有過一道類似的題,那個比較簡單好吧。
首先我們當我們連起一條線,我們可以把偶數之羊分成偶數與偶數,但無論如何也不能把奇數分成偶數與偶數,因此我們判斷兩點之間能不能連邊,只需要判斷兩邊的羊是否都是偶數只。
這裏我們就需要將這些點按照一個比較舒服的方式排序(比如說順時針或者是逆時針)。於是就用到了極角排序。其實看張圖就知道這個排序是幹什麼的了:
當然這個排序可以使用反三角函數
向量的叉積:
公式:
- 當
res>0 時,表示a⃗ 在b⃗ 的順時針方向 - 當
res<0 時,表示a⃗ 在b⃗ 的逆時針方向 - 當
res=0 時,表示a⃗ 與b⃗ 共線
於是極角排序的代碼就可以寫出來了。調用
struct Point{
int x,y;
Point operator -(const Point &a)const{
return (Point){x-a.x,y-a.y};
}
int operator *(const Point &a)const{
return x*a.y-a.x*y;
}
}A[M],now;
bool cmp(Point a,Point b){
return (a-now)*(b-now)<0;
}
注意點:極角排序的點與基準點連線的最大角度不能超過
然後對於這道題,就可以用這種方法直接處理出哪兩個點之間可以連邊,dp方程就顯而易見了。
於是就解決了這道題,複雜度
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define M 605
#define N 20005
using namespace std;
struct Point{
int x,y;
Point operator -(const Point &a)const{
return (Point){x-a.x,y-a.y};
}
int operator *(const Point &a)const{
return x*a.y-a.x*y;
}
}Q[M],K[N],now;
bool cmp(Point a,Point b){
return (a-now)*(b-now)<0;
}
int mp[M][M],dp[M][M],m;
int dfs(int L,int R){
int &res=dp[L][R];
if(res!=-1)return res;
res=0;
for(int i=L+1;i<R;i++){
if(mp[L][i]&&mp[i][R]){
res=(res+1LL*dfs(L,i)*dfs(i,R))%m;
}
}
return res;
}
int main(){
int n,k;
memset(dp,-1,sizeof(dp));
scanf("%d %d %d",&n,&k,&m);
for(int i=1;i<=n;i++)
scanf("%d %d",&Q[i].x,&Q[i].y);
for(int i=1;i<=k;i++)
scanf("%d %d",&K[i].x,&K[i].y);
now=Q[1];
sort(Q+2,Q+n+1,cmp);
for(int i=1;i<=n;i++){
now=Q[i];
sort(K+1,K+k+1,cmp);
int res=0;
for(int j=i+1;j<=n;j++){
while(res<k&&(K[res+1]-now)*(Q[j]-now)<0)res++;
if(res&1||(K[res+1]-now)*(Q[j]-now)==0)continue;
mp[i][j]=mp[j][i]=true;
}
}
for(int i=1;i<n;i++)
dp[i][i+1]=1;
printf("%d\n",dfs(1,n));
return 0;
}