FJ省队集训DAY2 T2

思路:我们可以考虑三角剖分,这样问题就变成考虑三角形的选取概率和三角形内有多少个点了。

先用树状数组预处理出三角剖分的三角形中有多少个点,然后用线段树维护,先用原点极角排序,然后枚举i,再以i极角排序,此时线段树的作用就来了,每次到一个询问的教室点,我们就在线段树里面查找之前的概率,统计贡献即可。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<algorithm>
  6 #define MAXN 2005
  7 struct Point{
  8     double x,y;
  9     double p,ang;
 10     int id;
 11 }p[MAXN],Cur[MAXN];
 12 double P[MAXN],T[MAXN * 4];
 13 int n,m,rk[MAXN],s[MAXN],f[MAXN][MAXN];
 14 int read(){
 15     int t=0,f=1;char ch=getchar();
 16     while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘)f=-1;ch=getchar();}
 17     while (‘0‘<=ch&&ch<=‘9‘){t=t*10+ch-‘0‘;ch=getchar();}
 18     return t*f;
 19 }
 20 bool cmp(Point p1,Point p2){
 21     return p1.ang<p2.ang;
 22 }
 23 void build (int k,int l,int r){
 24     if (l==r) {T[k]=1-P[Cur[l].id];return;}
 25     int mid=(l+r)>>1;
 26     build(k*2,l,mid);
 27     build(k*2+1,mid+1,r);
 28     T[k]=T[k*2]*T[k*2+1];
 29 }
 30 double query(int k,int l,int r,int x,int y){
 31     if (y<l||x>r) return 1.0;
 32     if (l==x&&r==y) return T[k];
 33     int mid=(l+r)>>1;
 34     if (y<=mid) return query(k*2,l,mid,x,y);
 35     else
 36     if (x>mid) return query(k*2+1,mid+1,r,x,y);
 37     else return query(k*2,l,mid,x,mid)*query(k*2+1,mid+1,r,mid+1,y);
 38 }
 39 void init(){
 40     n=read();m=read();
 41     for (int i=1;i<=n;i++)
 42       scanf("%lf%lf",&p[i].x,&p[i].y),p[i].id=i;
 43     for (int i=n+1;i<=n+m;i++)
 44       scanf("%lf%lf%lf",&p[i].x,&p[i].y,&P[i]),p[i].id=i;
 45     for (int i=1;i<=n+m;i++)
 46      p[i].ang=atan2(p[i].y,p[i].x);
 47 }
 48 void add(int pos){
 49     for (;pos<=n+m;pos+=(pos)&(-pos)) s[pos]++;
 50 }
 51 int sum(int pos){
 52     int res=0;
 53     for (;pos;pos-=(pos)&(-pos)) res+=s[pos];
 54     return res;
 55 }
 56 void Sort(int mid){
 57     int tot=0;
 58     for (int i=0;i<=n+m;i++)
 59      if (i!=mid) Cur[++tot]=p[i],Cur[tot].ang=atan2(Cur[tot].y-p[mid].y,Cur[tot].x-p[mid].x);
 60     std::sort(Cur+1,Cur+1+tot,cmp);
 61     for (int i=1;i<=tot;i++) rk[Cur[i].id]=i;
 62 }
 63 int range(int l,int r){
 64     if (l<=r) return sum(r)-sum(l-1);
 65     return sum(n+m)-sum(l-1)+sum(r);
 66 }
 67 void solve(){
 68     std::sort(p+1,p+1+n+m,cmp);
 69     for (int i=1;i<=n+m+1;i++)
 70      if (p[i].id>n){
 71             Sort(i);
 72             for (int j=0;j<=n+m;j++) s[j]=0;
 73             for (int j=i+1;j<=n+m+1;j++){
 74                 if (p[j].id<=n&&p[j].id) add(rk[p[j].id]);
 75                 f[p[i].id][p[j].id]=std::max(0,range(rk[p[j].id],rk[0]));
 76             }
 77             for (int j=0;j<=n+m;j++) s[j]=0;
 78             for (int j=i-1;j;j--){
 79                 if (p[j].id<=n&&p[j].id) add(rk[p[j].id]);
 80                 f[p[i].id][p[j].id]=std::max(0,range(rk[0],rk[p[j].id]));
 81             }
 82      }
 83 }
 84 double ask(int l,int r){
 85     if (l>r) return query(1,1,n+m-1,l,n+m-1)*query(1,1,n+m-1,1,r-1);
 86     else return query(1,1,n+m-1,l,r-1);
 87 }
 88 void linear(){
 89     double ans=0.0;
 90     int tot=0;
 91     for (int i=1;i<=n+m;i++)
 92      if (p[i].id>n){
 93             tot=0;
 94             for (int j=1;j<=n+m;j++)
 95              if (i!=j) Cur[++tot]=p[j],Cur[tot].ang=atan2(p[j].y-p[i].y,p[j].x-p[i].x);
 96             std::sort(Cur+1,Cur+1+tot,cmp);
 97             build(1,1,tot);
 98             for (int j=1,Pp=1;j<=tot;j++){
 99                 for(;(Cur[j].x - p[i].x) * (Cur[Pp].y - p[i].y) - (Cur[j].y - p[i].y) * (Cur[Pp].x - p[i].x) > 0;) Pp=Pp%tot+1;
100                 if (Cur[j].id>n){
101                     double pr=ask(Pp,j)*P[p[i].id]*P[Cur[j].id];
102                     if (p[i].x * Cur[j].y - p[i].y * Cur[j].x < 0)
103                         ans -= pr * f[p[i].id][Cur[j].id]; else
104                         ans += pr * f[p[i].id][Cur[j].id];
105                      }
106                 }
107             }
108     printf("%.9lf\n",ans);
109 }
110 int main(){
111     init();
112     solve();
113     linear();
114 }
时间: 2024-10-18 06:10:10

FJ省队集训DAY2 T2的相关文章

FJ省队集训DAY2 T1

思路:转换成n条三维空间的直线,求最大的集合使得两两有交点. 有两种情况:第一种是以某2条直线为平面,这时候只要统计这个平面上有几条斜率不同的直线就可以了 还有一种是全部交于同一点,这个也只要判断就可以了. 然后我并不能改出来,wa了好多个点 WA的程序: 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm&

FJ省队集训DAY4 T2

XXX 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<vector> 7 using namespace std; 8 typedef unsigned long long ll; 9 ll a,mod=1,L=1; 10 ll tr[4],b[4],tmp[4

FJ省队集训DAY3 T2

思路:如果一个DAG要的路径上只要一条边去切掉,那么要怎么求?很容易就想到最小割,但是如果直接做最小割会走出重复的部分,那我们就这样:反向边设为inf,这样最小割的时候就不会割到了,判断无解我们直接用tarjan 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define ll long

FJ省队集训最终测试 T2

思路:发现如果一个人一共选了x个点,那么选中某一个点对的概率都是一样的,一个人选x个点的总方案是C(n,x),一个人选中某个点对的总方案是C(n-2,x-2),这样,那么选中某个点对的概率就是 x*(x-1)/(n*(n-1)),这样,我们就用树分治求出有多少对符合条件的对数,然后乘上每个人的概率即可. 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring>

FJ省队集训DAY1 T1

题意:有一堆兔子,还有一个r为半径的圆,要求找到最大集合满足这个集合里的兔子两两连边的直线不经过圆. 思路:发现如果有两个点之间连边不经过圆,那么他们到圆的切线会构成一段区间,那么这两个点的区间一定会有交集,形如s0 s1 e0 e1 同样的,如果是n个点,那就是s0 s1 s2..sn e0 e1 e2.. en 因此,我们枚举那个起始点,然后对于其他点我们按照s排序,对于e做最长上升子序列即可.时间复杂度O(n^2 logn) 1 #include <cstdio> 2 #include

FJ省队集训DAY3 T1

思路:我们考虑如果取掉一个部分,那么能影响到最优解的只有离它最近的那两个部分. 因此我们考虑堆维护最小的部分,离散化离散掉区间,然后用线段树维护区间有没有雪,最后用平衡树在线段的左右端点上面维护最小的id 我讲的貌似不是很清楚.. 还有,蜜汁80分,打死也改不出来.. 1 #include<cstdio> 2 #include<cmath> 3 #include<iostream> 4 #include<cstring> 5 #include<algo

FJ省队集训DAY5 T1

思路:考试的时候打了LCT,自以为能过,没想到只能过80.. 考完一想:lct的做法点数是100W,就算是nlogn也会T. 讲一下lct的做法把:首先如果一条边连接的两个点都在同一个联通块内,那么这条边对答案没有影响,可以忽略,因此,问题变成了每次询问两个点中路径上权值最大的边(这里的权值我们令它为加入这条边的时间),边我们用一个点连接两个端点来表示. 正解:由于是无根树,因此我们用并查集按秩合并,每次把小的加到大的里面去,询问的时候暴力走lct查找最大即可. 1 #include<cstdi

FJ省队集训DAY4 T1

直接上题解 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define ll long long 7 const int Mod=1000000009,N=3000; 8 ll jc[N+10],jcny[N+10],jcnys[N+10],K[N+10],p[N+10],f[N+10];

FJ省队集训最终测试 T3

思路:状态压缩dp,f[i][j[[k]代表i行j列这个格子,连续的状态为k,这个连续的状态是什么?就是下图 X格子代表我当前走到的地方,而这里的状态就是红色部分,也就是连续的一段n的状态,我们是分每一位计算的,这样就可以转移了,注意,当当前点在最下面的时候要额外计算一个与1的贡献. 坑爹,inf设小了只有30分. 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstrin