题目大意
平面上有
个基站,每个基站有
种可能的类型。若一种类型的基站恰好是另一种类型的两个基站的中点,则该基站会受到那对基站的干扰。求每个基站受到的干扰数。
数据范围
对于
的数据,
对于
的数据,
对于
的数据,
对于
的数据,
对于
的数据,
题解
首先,暴力是很好打的,三十分到手。可惜的是,许多人只拿了三十分。
因为五十分也是可以做的,先对基站分类,然后按照基站的类型做三次暴力,如果你有非常小心常数的习惯,你是完全可以卡过去的。
下面来说正解。
注意到
和
非常小,因此我们可以转换为一维问题。
设
,则条件"
是
的中点"的条件与
等价。
充分性证明:
是
的中点
必要性证明:
式减去
式得:
接下来,问题变为:直线上有
个基站,每个基站有
种可能的类型。若一种类型的基站恰好是另一种类型的两个基站的中点,则该基站会受到那对基站的干扰。求每个基站受到的干扰数。下面只考虑类型为0的基站,其余的类似。
构造序列
,然后计算序列
。
由卷积的定义式可得:
当
为奇数的时候,
由两个和为奇数的位置组成,它们的中点不在整数点上,因此可以忽略。
而只有当
为偶数的时候,产生贡献的两个点才会在整数点上,而且会被重复算两次,因此最后统计答案的时候要除以
。
//O2下AC
#include<bits/stdc++.h>
using namespace std;
const int maxn=2097153;
const double pi=acos(-1.0);
struct comp{
double x,y;
comp(double xx=0,double yy=0):x(xx),y(yy) {}
friend comp operator+(const comp &x,const comp &y) {return comp(x.x+y.x,x.y+y.y);}
friend comp operator-(const comp &x,const comp &y) {return comp(x.x-y.x,x.y-y.y);}
friend comp operator*(const comp &a,const comp &b) {return comp(a.x*b.x-a.y*b.y,a.x*b.y+b.x*a.y);}
}a[maxn],b[maxn],c[maxn];
int limit=1,l=0,r[maxn];
int reset(int n,int m){
while(limit<=n+m)
limit<<=1,++l;
for(int i=1;i<limit;i++)
r[i]=((r[i>>1]>>1)|((i&1)<<(l-1)));
}
void fft(comp *t,int ty){
for(int i=0;i<limit;i++)
if(i<r[i])
swap(t[i],t[r[i]]);
for(int mid=1;mid<limit;mid<<=1){
comp wn(cos(pi/mid),ty*sin(pi/mid));
for(int j=0,R=(mid<<1);j<limit;j+=R){
comp w(1,0);
for(int k=0;k<mid;k++,w=w*wn){
comp x=t[j+k],y=w*t[j+k+mid];
t[j+k]=x+y;
t[j+k+mid]=x-y;
}
}
}
}
#define Maxn 510000
int n,pos[Maxn],d[Maxn];
int ts[Maxn],pd[Maxn],mx;
void dos(comp *a,int k){
fft(a,1);for(int i=0;i<limit;i++) a[i]=a[i]*a[i]; fft(a,-1);
for(int i=0;i<=mx*2;i+=2){
if(pd[i/2]==k||pd[i/2]==0) continue;
ts[i/2]+=(int)floor(a[i].x/limit+0.001)/2;
}
}
int main(void)
{
scanf("%d",&n);
for(int i=1,x,y;i<=n;i++){
scanf("%d%d%d",&x,&y,&d[i]);
pd[pos[i]=x*1000+y]=++d[i];
mx=max(mx,pos[i]);
}
for(int i=1;i<=n;i++){
if(d[i]==1) a[pos[i]].x=1;
if(d[i]==2) b[pos[i]].x=1;
if(d[i]==3) c[pos[i]].x=1;
}
reset(mx+1,mx+1);
dos(a,1);dos(b,2);dos(c,3);
for(int i=1;i<=n;i++)
printf("%d\n",ts[pos[i]]);
return 0;
}