bzoj3513 [MUTC2013]idiots FFT

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/84889380

Description


给定n个长度分别为a_i的木棒,问随机选择3个木棒能够拼成三角形的概率。

第一行T(T<=100),表示数据组数。
接下来若干行描述T组数据,每组数据第一行是n,接下来一行有n个数表示a_i。
3≤N≤105,1≤a_i≤105

T<=20
N<=100000

Solution


考虑算不能拼成三角形的概率。我们设f[x]表示两条边组成x的方案数,统计比x大的边有多少直接算就可以了
求f[]可以FFT

感觉压一波时间就可以进第一页了呀。。

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#define rep(i,st,ed) for (register int i=st;i<=ed;++i)
#define drp(i,st,ed) for (register int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))
 
typedef long long LL;
 
const int N=444489;
const double pi=3.1415926535897932;
 
struct com {
	double real,imag;
	com operator +(const com &b) const {return (com) {real+b.real,imag+b.imag};}
	com operator -(const com &b) const {return (com) {real-b.real,imag-b.imag};}
	com operator *(const com &b) const {return (com) {real*b.real-imag*b.imag,real*b.imag+imag*b.real};}
	com operator /(const double b) const {return (com) {real/b,imag/b};}
} a[N];
 
int rev[N],c[N];
 
int read() {
	int x=0,v=1; char ch=getchar();
	for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
	for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
	return x*v;
}
 
void FFT(com *a,int len,double f) {
	for (register int i=0;i<len;i++) if (i<rev[i]) std:: swap(a[i],a[rev[i]]);
	for (register int i=1;i<len;i<<=1) {
		com wn=(com) {cos(pi/i),f*sin(pi/i)};
		for (register int j=0;j<len;j+=i*2) {
			com w=(com) {1,0};
			for (register int k=0;k<i;k++) {
				register int tmp=j+k;
				com u=a[tmp],v=a[tmp+i]*w;
				a[tmp]=u+v; a[tmp+i]=u-v;
				w=w*wn;
			}
		}
	}
	if (f==-1) for (register int i=0;i<len;i++) a[i]=a[i]/len;
}
 
int main(void) {
	freopen("data.in","r",stdin);
	freopen("myp.out","w",stdout);
	for (int T=read();T--;fill(c,0)) {
		int n=read(),mx=0;
		rep(i,1,n) {
			int x=read(); c[x]+=1;
			mx=std:: max(mx,x);
		}
		int len,lg; for (len=1,lg=0;len<=mx*2;len<<=1,lg++);
		for (register int i=0;i<len;++i) rev[i]=(rev[i/2]/2)|((i&1)<<(lg-1)),a[i].real=c[i],a[i].imag=0;
		FFT(a,len,1);
		for (register int i=0;i<len;++i) a[i]=a[i]*a[i];
		FFT(a,len,-1);
		for (register int i=0;i<len;i+=2) a[i].real-=1.0*c[i>>1];
		for (register int i=0;i<len;++i) a[i]=a[i]/2.0;
		LL ans=0;
		drp(i,mx,0) c[i]+=c[i+1];
		rep(i,0,len-1) ans+=(LL)(0.5+a[i].real)*c[i];
		LL tmp=1LL*n*(n-1)/2*(n-2)/3;
		printf("%.7lf\n", 1.0*(tmp-ans)/tmp);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/84889380
FFT