您的位置:首页 > 大数据 > 物联网

HDU 4609 3-idiots FFT+容斥

2016-07-20 22:30 381 查看
一点吐槽:我看网上很多分析,都是在分析这个题的时候,讲了半天的FFT,其实我感觉更多的把FFT当工具用就好了

分析:这个题如果数据小,统计两个相加为 x 的个数这一步骤(这个步骤其实就是求卷积啊),完全可以母函数,无奈数据很大,就用FFT了

然后难点在于最后的统计,要减去自身,两个都大的,一大一小,包含自身,这是用到了容斥,再做相似的题的时候,应该多看看这方面

注:再次高度仰慕kuangbin神,这是我FFT的第二题,也是第二次用kuangbin FFT模板

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <map>
using namespace std;
typedef long long LL;
const int INF=0x3f3f3f3f;
const int N=4e5+5;
const double pi = acos(-1.0);
struct complex{
double r,i;
complex(double R=0,double I=0){
r=R;i=I;
}
complex operator+(const complex &a)const{
return complex(r+a.r,i+a.i);
}
complex operator-(const complex &a)const{
return complex(r-a.r,i-a.i);
}
complex operator*(const complex &a)const{
return complex(r*a.r-i*a.i,r*a.i+i*a.r);
}
};
void change(complex x[],int len){
int i,j,k;
for(i=1,j=len/2;i<len-1;++i){
if(i<j)swap(x[i],x[j]);
k=len/2;
while(j>=k){j-=k;k>>=1;}
if(j<k)j+=k;
}
}
void fft(complex x[],int len,int on){
change(x,len);
for(int i=2;i<=len;i<<=1){
complex wn(cos(-on*2*pi/i),sin(-on*2*pi/i));
for(int j=0;j<len;j+=i){
complex w(1,0);
for(int k=j;k<j+i/2;++k){
complex u = x[k];
complex t = w*x[k+i/2];
x[k]=u+t;
x[k+i/2]=u-t;
w=w*wn;
}
}
}
if(on==-1)for(int i=0;i<len;++i)x[i].r/=len;
}
complex x
;
int a[N>>1];
LL num
,sum
;
int main(){
int T,n;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
memset(num,0,sizeof(num));
for(int i=0;i<n;++i){scanf("%d",&a[i]);++num[a[i]];}
sort(a,a+n);
int len1 = a[n-1] + 1,len = 1;
while(len<2*len1)len<<=1;
for(int i=0;i<len1;++i)x[i]=complex(num[i],0);
for(int i=len1;i<len;++i)x[i]=complex(0,0);
fft(x,len,1);
for(int i=0;i<len;++i)x[i]=x[i]*x[i];
fft(x,len,-1);
for(int i=0;i<len;++i)
num[i]=(long long)(x[i].r+0.5);
len=2*a[n-1];
for(int i=0;i<n;++i)--num[a[i]+a[i]];
for(int i=1;i<=len;++i)num[i]>>=1;
for(int i=1;i<=len;++i)sum[i]=sum[i-1]+num[i];
LL cnt=0;
for(int i=0;i<n;++i){
cnt+=sum[len]-sum[a[i]];
cnt-=1ll*(n-1-i)*i;
cnt-=(n-1);
cnt-=1ll*(n-1-i)*(n-i-2)/2;
}
LL tot=1ll*n*(n-1)*(n-2)/6;
printf("%.7f\n",1.0*cnt/tot);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: