KD树+bitset
对于一个联盟s,设会打它的个数为t,那它对答案的贡献就是 (n−tn)m
考虑怎么得到t。对于一个点,我们希望在它能打到的所有点上面打上这个点的标记。直接打标记不行,考虑用KD树即可。然后联盟里的所有点用bitset或起来即可得到所有能打到这个联盟的点。
题目保证了坐标随机,因此KD树的复杂度是期望 n‾√ 的。
#include<cmath>
#include<bitset>
#include<cstdio>
#include<algorithm>
#define N 35005
using namespace std;
namespace runzhe2000
{
typedef double db;
int n, m, k, nocnt, D, rebel[N*5], vis[N];
struct point
{
int x, y, r, a, bel;
bool operator < (const point &that) const {return D ? x < that.x : y < that.y;}
}p[N];
struct node{int id, next;}no[N*300];
struct KDT{int x[2], y[2], list;}t[N*5];
bitset<N> tmp, f[N];
void build(int x, int l, int r, int d)
{
D = d; t[x].list = 0; if(l == r) {rebel[x] = p[l].bel; t[x].x[0] = t[x].x[1] = p[l].x, t[x].y[0] = t[x].y[1] = p[l].y; return;}
int mid = (l+r)>>1; nth_element(p+l, p+mid, p+r+1); build(x<<1,l,mid,d^1); build(x<<1|1,mid+1,r,d^1);
t[x].x[0] = min(t[x<<1].x[0], t[x<<1|1].x[0]); t[x].x[1] = max(t[x<<1].x[1], t[x<<1|1].x[1]);
t[x].y[0] = min(t[x<<1].y[0], t[x<<1|1].y[0]); t[x].y[1] = max(t[x<<1].y[1], t[x<<1|1].y[1]);
}
int mabs(int x){return x<0?-x:x;}
int msqr(int x){return x*x;}
void query(int x, int l, int r, int d, int id)
{
if(max(p[id].x - t[x].x[0], t[x].x[1] - p[id].x) + max(p[id].y - t[x].y[0], t[x].y[1] - p[id].y) <= p[id].a
|| sqrt((db)(msqr(max(p[id].x - t[x].x[0], t[x].x[1] - p[id].x)) + msqr(max(p[id].y - t[x].y[0], t[x].y[1] - p[id].y)))) <= p[id].r)
{no[++nocnt] = (node){id, t[x].list}, t[x].list = nocnt; return;}
if(max(p[id].x-t[x].x[1],0)+max(t[x].x[0]-p[id].x,0)+max(p[id].y-t[x].y[1],0)+max(t[x].y[0]-p[id].y,0) > p[id].a
&& sqrt((db)(msqr(max(p[id].x-t[x].x[1],0)+max(t[x].x[0]-p[id].x,0))+msqr(max(p[id].y-t[x].y[1],0)+max(t[x].y[0]-p[id].y,0)))) > p[id].r)
return;
int mid = (l+r)>>1; query(x<<1,l,mid,d^1,id); query(x<<1|1,mid+1,r,d^1,id);
}
void search(int x, int l, int r)
{
for(int i = t[x].list; i; i = no[i].next) tmp.set(no[i].id);
if(l == r) f[rebel[x]] |= tmp;
else {int mid = (l+r)>>1; search(x<<1,l,mid); search(x<<1|1,mid+1,r);}
for(int i = t[x].list; i; i = no[i].next) tmp.reset(no[i].id);
}
db fpow(db a, int b)
{
db r = 1;
for(; b; b>>=1)
{
if(b&1)r=r*a;
a=a*a;
}
return r;
}
void main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i = 1; i <= n; i++)
scanf("%d%d%d%d%d",&p[i].x,&p[i].y,&p[i].r,&p[i].a,&p[i].bel);
build(1,1,n,0); for(int i = 1; i <= n; i++) query(1,1,n,0,i);
tmp.reset(); search(1,1,n);
for(int i = 1; i <= n; i++) f[p[i].bel].reset(i);
db ans = 0;
for(int i = 1; i <= k; i++)
ans += fpow((db)(n-f[i].count())/n, m);
printf("%.5lf\n",ans);
}
}
int main()
{
runzhe2000::main();
}