hdu 4609 3-idiots (FFT + 计数)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4609

(fft) 经典套路,求 (n) 个数任意两个相加所得的数的种类/数量,只需要将数值当作指数,系数0/1表示有/没有或 (a_i) 表示该数值有 (a_i) 个,(fft) 即可,注意去重

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;

const int maxn = 3e5+7;
 
int T, n, m, N = 100000;
int l,r[maxn], t[maxn], c[maxn];
ll ans[maxn], sum[maxn];
int lim=1;

const double Pi = acos(-1.0);
struct complex{
	double x,y;
	complex(double xx=0,double yy=0) { x=xx,y=yy; }
}a[maxn],b[maxn];
complex operator + (complex a,complex b) { return complex(a.x+b.x,a.y+b.y); }
complex operator - (complex a,complex b) { return complex(a.x-b.x,a.y-b.y); }
complex operator * (complex a,complex b) { return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x); } 

void fft(complex *A,int type){
	for(int i=0;i<lim;i++)
		if(i<r[i]) swap(A[i],A[r[i]]);
	for(int mid=1;mid<lim;mid<<=1){
		complex Wn( cos(Pi/mid),type*sin(Pi/mid));
		for(int r=mid<<1,j=0;j<lim;j+=r){
			complex w(1,0);
			for(int k=0;k<mid;k++,w=w*Wn){
				complex x=A[j+k],y=w*A[j+mid+k];
				A[j+k]=x+y;
				A[j+mid+k]=x-y;
			}
		}
	}
}

ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }

int main(){
	T = read();
	while(T--){
		memset(a, 0, sizeof(a));
		memset(b, 0, sizeof(b));
		memset(t, 0, sizeof(t));
		memset(c, 0, sizeof(c));
		memset(ans, 0, sizeof(ans));
		lim = 1, l = 0;
		n=read();
		for(int i = 1 ; i <= n ; ++i) t[i] = read(), ++c[t[i]];
		for(int i=0;i<=N;i++) a[i].x = c[i];
		
		while(lim <= N + N) lim<<=1,l++;
		for(int i=0;i<lim;i++)
			r[i]=(r[i>>1]>>1)|(i&1)<<(l-1);
		fft(a,1);
		for(int i=0;i<=lim;i++) a[i]=a[i]*a[i];
		fft(a,-1);
		for(int i=0;i<=N + N;i++){
			ans[i] = (ll)(a[i].x/lim+0.5);
		}	
		
		for(int i = 1 ; i <= n ; ++i) --ans[t[i] + t[i]]; 
		for(int i = 0 ; i <= N + N ; ++i) {
			ans[i] /= 2ll;
		}
		
		for(int i = 1 ; i <= N + N ; ++i){
			sum[i] = sum[i - 1] + ans[i];
		}
		
		ll val = 0;
		for(int i = 1 ; i <= n ; ++i){
			val += sum[N + N] - sum[t[i]];
			val -= 1ll * (i - 1) * (n - i);
			val -= (n - 1);
			val -= 1ll * (n - i) * (n - i - 1) / 2;
		}
		ll all = 1ll * n * (n - 1) * (n - 2) / 6ll;
		printf("%.7lf
", (double) val / all);
	}

	return 0;
}
原文地址:https://www.cnblogs.com/tuchen/p/14386636.html