HDU 4609 3-idiots

来源:互联网 发布:mac搜不到蓝牙耳机 编辑:程序博客网 时间:2024/05/22 10:51
Problem Description
King OMeGa catched three men who had been streaking in the street. Looking as idiots though, the three men insisted that it was a kind of performance art, and begged the king to free them. Out of hatred to the real idiots, the king wanted to check if they were lying. The three men were sent to the king's forest, and each of them was asked to pick a branch one after another. If the three branches they bring back can form a triangle, their math ability would save them. Otherwise, they would be sent into jail.
However, the three men were exactly idiots, and what they would do is only to pick the branches randomly. Certainly, they couldn't pick the same branch - but the one with the same length as another is available. Given the lengths of all branches in the forest, determine the probability that they would be saved.
 

Input
An integer T(T≤100) will exist in the first line of input, indicating the number of test cases.
Each test case begins with the number of branches N(3≤N≤105).
The following line contains N integers a_i (1≤a_i≤105), which denotes the length of each branch, respectively.
 

Output
Output the probability that their branches can form a triangle, in accuracy of 7 decimal places.
 

Sample Input
241 3 3 442 3 3 4
 

Sample Output
0.50000001.0000000
 

Source
2013 Multi-University Training Contest 1
 

Recommend

liuyiding

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

FFT+容斥原理+神奇的思路~

……为什么FFT总是被包装得根本看不出来呢?

先把a[i]排序使之单调。

注意到a[i]很小,我们可以开一个数组sum[i]来存a[k]=i的k有多少个,然后sum和自己卷积得到sum[i]数组,表示选取两根木棍使得它们的和为i的方案数,但是这里有同时取了同一根木棍的,所以sum[a[i]+a[i]]--;然后,取ij和取ji是同一种情况,所以sum[i]/=2;再把sum[i]求一下前缀和,方便区间求值。

下面,我们枚举三角形中最大的一边的长度a[i],那么能与它组成三角形的边j、k一定满足a[j]+a[k]>a[i] && j<i && k<i,所以对于一个a[i],操作包括:

ans+=num[maxx]-num[a[i]];

ans-=(ll)(i-1)*(nn-i)(减去jk一大一小的情况);

ans-=nn-1(减去j==i || k==i的情况);

ans-=(ll)(nn-i)*(nn-i-1)/2(减去j>i && k>i的情况)。

然后,ans就是满足条件的组数;选择(不一定满足条件)共有tot=nn*(n-1)*(nn-2)/6种,概率就是ans/tot,注意要强制转化~

另外,由于程序中用到FFT,我用nn来代表题目中的n,而我的n是FFT模板中用到的极限n(或者称为len)~


#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>using namespace std;#define ll long long#define pi acos(-1)#define N 400040#define M 100001int t,n,nn,a[M],maxx,l;ll num[N],ans,r[N];struct E{double r,i;E (double u,double v) {r=u;i=v;}E () {}E operator + (E u) {return E(u.r+r,u.i+i);}E operator - (E u) {return E(r-u.r,i-u.i);}E operator * (E u) {return E(r*u.r-i*u.i,r*u.i+i*u.r);}}f1[N];E operator / (E u,int v) {return E(u.r/v,u.i/v);}int read(){int totnum=0;char ch=getchar();while(ch<'0' || ch>'9') ch=getchar();while(ch>='0' && ch<='9') {totnum=(totnum<<1)+(totnum<<3)+ch-'0';ch=getchar();}return totnum;}void fft(E *u,int v){for(int i=0;i<n;i++) if(i<r[i]) swap(u[i],u[r[i]]);for(int i=1;i<n;i<<=1){E wn(cos(pi/i),v*sin(pi/i));for(int j=0;j<n;j+=(i<<1)){E w(1,0);for(int k=0;k<i;k++,w=w*wn){E x=u[j+k],y=w*u[i+j+k];u[j+k]=x+y;u[i+j+k]=x-y;}}}if(v==-1) for(int i=0;i<n;i++) u[i]=u[i]/n;}int main(){t=read();while(t--){nn=read();l=ans=0;memset(num,0,sizeof(num));for(int i=1;i<=nn;i++) a[i]=read(),num[a[i]]++;sort(a+1,a+nn+1);maxx=a[nn]+1;for(n=1;n<2*maxx;n<<=1) l++;for(int i=0;i<n;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));for(int i=0;i<maxx;i++) f1[i]=E(num[i],0);for(int i=maxx;i<n;i++) f1[i]=E(0,0);fft(f1,1);for(int i=0;i<n;i++) f1[i]=f1[i]*f1[i];fft(f1,-1);for(int i=0;i<n;i++) num[i]=(ll)(f1[i].r+0.5);for(int i=1;i<=nn;i++) num[a[i]+a[i]]--;for(int i=0;i<=n;i++) num[i]/=2;for(int i=1;i<=n;i++) num[i]+=num[i-1];for(int i=1;i<=nn;i++){ans+=num[n]-num[a[i]];ans-=(ll)(i-1)*(nn-i);ans-=nn-1;ans-=(ll)(nn-i)*(nn-i-1)/2;}printf("%.7lf\n",(double)ans*6/nn/(nn-1)/(nn-2));}return 0;}


1 0
原创粉丝点击