题面
http://codeforces.com/contest/1146/problem/H
题解
由于五角星难以统计,并且一个五角星唯一对应它的外接五边形,考虑统计原图中凸五边形的数量。
设dp(i,j,k)表示从i号点开始,走到j号点结束,一共经过k个点,且经过的所有点顺次连接形成的路径为向量i->j右侧的凸包的方案数。
初始时,所有的dp(i,i,1)为1,其他为0。将图中所有的有向线段按极角升序排序,然后顺次枚举;设当前枚举到的有向线段是由第u号点连向第v号点的,那么枚举i,j,并进行转移dp(i,v,j+1) += dp(i,u,j)。极角排序的好处是不会破坏凸性,此式得以成立。
最终对所有dp(i,i,6)求和即可。
时间复杂度(O(n^3))。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rg register
#define In inline
const ll N = 300;
typedef pair<ll,ll>pll;
In ll read(){
ll s = 0,ww = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
return s * ww;
}
struct vec{
ll x,y;
vec(){}
vec(ll _x,ll _y){x = _x,y = _y;}
In friend vec operator - (vec a,vec b){
return vec(a.x - b.x,a.y - b.y);
}
In friend ll Cross(vec a,vec b){
return a.x * b.y - a.y * b.x;
}
In friend bool InUpper(vec a){
return a.y > 0 || (a.y == 0 && a.x > 0);
}
}p[N+5];
In bool cmp(pll i,pll j){ //极角排序
vec a = p[i.second] - p[i.first],b = p[j.second] - p[j.first];
bool k1 = InUpper(a),k2 = InUpper(b);
if(k1 != k2)return k1 < k2;
return Cross(a,b) > 0;
}
ll f[N+5][N+5][7];
ll n;
pll seg[N*N+5];
int main(){
n = read();
for(rg int i = 1;i <= n;i++){
ll x = read(),y = read();
p[i] = vec(x,y);
}
int cnt = 0;
for(rg int i = 1;i <= n;i++)
for(rg int j = 1;j <= n;j++)if(i != j)seg[++cnt] = make_pair(i,j);
sort(seg + 1,seg + cnt + 1,cmp);
for(rg int i = 1;i <= n;i++)f[i][i][1] = 1;
for(rg int k = 1;k <= cnt;k++){
int u = seg[k].first,v = seg[k].second;
for(rg int i = 1;i <= n;i++)
for(rg int j = 1;j <= 5;j++)f[i][v][j+1] += f[i][u][j];
}
ll ans = 0;
for(rg int i = 1;i <= n;i++)ans += f[i][i][6];
cout << ans << endl;
return 0;
}