2019.01.02 bzoj3513: [MUTC2013]idiots(fft)

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/85616404

传送门
f f t fft 经典题。
题意简述:给定 n n 个长度分别为 a i a_i 的木棒,问随机选择3个木棒能够拼成三角形的概率。


思路:考虑对于木棒构造出生成函数然后可以 f f t fft 出两个木棒能够生成的边长和的生成函数 注意去重
我们还可以在读入的时候顺便统计出 c n t i cnt_i 表示长度 i \le i 的木棒有多少根。
然后可以算出选出3个木棒不能拼成三角形的方案数,简单容斥一下再算出总选法数即可。
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
typedef long long ll;
struct Cp{
	double x,y;
	Cp(double x=0.0, double y=0.0):x(x),y(y){};
	friend inline Cp operator+(const Cp&a,const Cp&b){return (Cp){a.x+b.x,a.y+b.y};}
	friend inline Cp operator-(const Cp&a,const Cp&b){return (Cp){a.x-b.x,a.y-b.y};}
	friend inline Cp operator*(const double&a,const Cp&b){return (Cp){a*b.x,a*b.y};}
	friend inline Cp operator*(const Cp&a,const Cp&b){return (Cp){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};}
	friend inline Cp operator/(const Cp&a,const double&b){return (Cp){a.x/b,a.y/b};}
};
int lim,tim;
vector<Cp>A,B;
vector<int>pos;
inline void init(const int&up){
	lim=1,tim=0;
	while(lim<=up)lim<<=1,++tim;
	pos.resize(lim),A.resize(lim),B.resize(lim),pos[0]=0;
	for(ri i=0;i<lim;++i)pos[i]=(pos[i>>1]>>1)|((i&1)<<(tim-1));
}
const double pi=acos(-1.0);
inline void fft(vector<Cp>&a,const int&type){
	for(ri i=0;i<lim;++i)if(i<pos[i])swap(a[i],a[pos[i]]);
	for(ri mid=1;mid<lim;mid<<=1){
		Cp wn(cos(pi/mid),type*sin(pi/mid));
		for(ri j=0,len=mid<<1;j<lim;j+=len){
			Cp w(1,0),a0,a1;
			for(ri k=0;k<mid;++k,w=w*wn){
				a0=a[j+k],a1=a[j+k+mid]*w;
				a[j+k]=a0+a1,a[j+k+mid]=a0-a1;
			}
		}
	}
	if(type==-1)for(ri i=0;i<lim;++i)a[i]=a[i]/lim;
}
struct poly{
	vector<Cp>a;
	poly(int k=0,int x=0){a.resize(k+1),a[k]=x;}
	inline Cp&operator[](const int&k){return a[k];}
	inline const Cp&operator[](const int&k)const{return a[k];}
	inline int deg()const{return a.size()-1;}
	inline poly extend(const int&k){poly ret=*this;return ret.a.resize(k+1),ret;}
	friend inline poly operator*(const poly&a,const poly&b){
		int n=a.deg(),m=b.deg();
		init(n+m);
		poly ret(lim);
		for(ri i=0;i<=n;++i)A[i]=a[i];
		for(ri i=0;i<=m;++i)B[i]=b[i];
		for(ri i=n+1;i<lim;++i)A[i]=(0,0);
		for(ri i=m+1;i<lim;++i)B[i]=(0,0);
		fft(A,1),fft(B,1);
		for(ri i=0;i<lim;++i)A[i]=A[i]*B[i];
		return fft(A,-1),ret.a=A,ret;
	}
};
const int N=1e5+5;
int n,x[N],mx;
poly a;
ll sum,cnt[N*2];
int main(){
	for(ri tt=read();tt;--tt){
		fill(cnt,cnt+mx+1,0);
		n=read(),mx=0;
		for(ri i=1;i<=n;++i)mx=max(mx,x[i]=read()),++cnt[x[i]];
		for(ri i=1;i<=2*mx;++i)cnt[i]+=cnt[i-1];
		a=a.extend(mx);
		for(ri i=0;i<=mx;++i)a[i]=(0,0);
		for(ri i=1;i<=n;++i)a[x[i]].x+=1;
		a=a*a,mx<<=1;
		for(ri i=1;i<=n;++i)a[x[i]<<1].x-=1;
		sum=(ll)n*(n-1)*(n-2);
		for(ri i=1;i<=mx;++i)sum-=(ll)(a[i].x+0.5)*(cnt[i-1]-2);
		sum=(ll)n*(n-1)*(n-2)/6-sum/2;
		printf("%.7LF\n",(long double)(sum*6.0)/((long double)n*(n-1)*(n-2)));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/85616404