TC SRM 655 Div1 Level 3 题解
dp+几何
首先可以发现凸包是顺时针排列的一些线段构成的。我们可以预处理每一个蓝点是否都在一个线段(r[i] ightarrow r[j]),(箭头表示在凸包上的方向)的内测。
然后蓝点就没有用了。
然后再回想一下凸包的定义:所有点连接起来都是外凸的,且可以框住所有的点。
然后我们像构建凸包那样来dp。
首先钦定最下面,最靠左的点。然后将其它的极交排序。(dp_{i,j})表示当前凸包上的线段为(r[i]->r[j])的概率。
注意:需要判断凸包的凸性!
/*
{
######################
# Author #
# Gary #
# 2021 #
######################
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
// int x=0;
// char ch=getchar();
// while(ch<'0'||ch>'9'){
// ch=getchar();
// }
// while(ch>='0'&&ch<='9'){
// x=(x<<1)+(x<<3)+(ch^48);
// ch=getchar();
// }
// return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
struct vec{
int x,y;
vec (mp A){
x=A.FIR;
y=A.SEC;
}
vec (int A,int B){
x=A,y=B;
}
vec (){
}
bool operator * (vec oth){//返回叉乘结果是否>=0
return 1ll*x*oth.y>=1ll*y*oth.x;
}
vec operator - (vec oth){
return vec (x-oth.x,y-oth.y);
}
vec operator + (vec oth){
return vec(x+oth.x,y+oth.y);
}
};
bool cmp(vec A,vec B){
if(A.y!=B.y){
return A.y<B.y;
}
return A.x<B.x;
}
bool cmp_angle(vec A,vec B){//极角排序
return (B-A)*(vec(0,0)-A);
}
bool ok[120][120];
bool ok2[120][120];
double pro[120][120];
double dp[120][120];
map<mp,int> id;
class BichromeSky{
public:
double totallyCovered(vector<int> rx,vector<int> ry,vector<int> P,vector<int> bx,vector<int> by){
vector<vec> r,b;
int n=rx.size();
vector<double> p(n);
rep(i,n){
p[i]=P[i]/1000.0;
}
rep(i,n){
r.PB(vec(II(rx[i],ry[i])));
id[II(rx[i],ry[i])]=i;
}
rep(i,bx.size())
b.PB(vec(II(bx[i],by[i])));
sort(ALL(r),cmp);
sort(ALL(b),cmp);
rep(i,n) rep(j,n){
if(j==i) continue;
int idi,idj;
idi=id[II(r[i].x,r[i].y)];
idj=id[II(r[j].x,r[j].y)];
ok[idi][idj]=true;
rep(k,b.size()){
ok[idi][idj]&=(r[i]-b[k])*(r[j]-b[k]);
}
}
double rest=0;
double pp=1.0;
rep(i,n){
if(n-i<2) break;
deque<vec> oth;
for(int j=i+1;j<n;++j) oth.PB(r[j]-r[i]);
sort(ALL(oth),cmp_angle);
oth.push_front(vec(II(0,0)));
oth.PB(vec(II(0,0)));
int sz=oth.size();
vector<double> thisp(sz);
rep(j,sz){
vec now=oth[j]+r[i];
int idd=id[II(now.x,now.y)];
thisp[j]=p[idd];
}
rep(j,sz)
for(int k=j+1;k<sz;++k){
dp[j][k]=0.0;
pro[j][k]=1.0;
int idj,idk;
vec jv,kv;
jv=oth[j]+r[i];
kv=oth[k]+r[i];
idj=id[II(jv.x,jv.y)];
idk=id[II(kv.x,kv.y)];
ok2[j][k]=ok[idj][idk];
for(int l=j+1;l<k;++l){
if(!((oth[j]-oth[l])*(oth[k]-oth[l]))){
pro[j][k]*=1.0-thisp[l];
}
}
}
double tmp=0.0;
for(int j=1;j+1<sz;++j){
if(ok2[0][j])
dp[0][j]=thisp[j]*pro[0][j];
}
rep(j,sz)
for(int k=j+1;k<sz;++k){
for(int l=k+1;l<sz;++l){
if(ok2[k][l]&&(oth[l]-oth[k])*(oth[j]-oth[k])){
dp[k][l]+=dp[j][k]*thisp[l]*pro[k][l];
}
}
}
rep(j,sz){
if(ok2[j][sz-1])
tmp+=dp[j][sz-1];
}
tmp*=pp;
rest+=tmp;
pp*=(1.0-thisp[0]);
}
return rest;
}
};