您的位置:首页 > 大数据 > 人工智能

2013 Multi-University Training Contest 1

2016-11-20 10:28 423 查看

【4609HDU】3-idiots——组合计数+FFT

Time Limit: 10000/5000 MS (Java/Others)Memory Limit: 32768/32768 K (Java/Others)

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

2

4

1 3 3 4

4

2 3 3 4

Sample Output

0.5000000

1.0000000

我们记num[i]表示长度为i的线段的个数为num[i]个,那么对于输入的数组我们可以用一个多项式表示,f=a0x0+a1x1+a2x2⋯anxn即长度为次幂,个数为系数,那么如果两个相同的这样的多项式相乘呢??

很明显相乘之后的多项式的次幂表示两个线段长度和为s的个数为as当然这个和包括相同的线段,我们可以取出。sum[i]表示长度和为i的个数,那么sum[a[i]+a[i]]−−就可将同一条线段选两次的去掉。由于组合是有序的,而我们要的是无序,所以sum[i]/=2

我们定义s[i]是组成三角形中最长的边,s为和的长度大于s[i]的组合,那么ans+=s,但是在和s中存在不合法的组合我们需要去除。

1.一大一小的组合 ans−=(n−i−i)∗i

2.一个取自身,另一个任意的组合 ans−=(n−1)

3.两个都是大的组合 ans−=(n−1−i)×(n−2−i)/2

总的组合数是n×(n−1)×(n−2)6

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 2e5+100;
const double Pi = acos(-1.0);
struct Complex {
double real,imag;
Complex(){}
Complex(double _r,double _i):real(_r),imag(_i){}
Complex operator + (const Complex &a) const {
return Complex(real+a.real,imag+a.imag);
}
Complex operator -(const Complex &a) const {
return Complex(real-a.real,imag -a.imag);
}
Complex operator * (const Complex &a) const {
return Complex(real*a.real-imag*a.imag,real*a.imag+imag*a.real);
}
void SetValue(double r,double i) {
real = r; imag =  i;
}
void Output() {
printf("%lf %lf\n",real,imag);
}
}a[maxn*2];
int len,n,len1;
int s[maxn];
int num[maxn];
LL sum[maxn*2];
void Get() {
len = 1;
while(len<(2*len1)) len<<=1;
for(int i=0;i<len1;i++) a[i].SetValue(num[i],0);
for(int i = len1;i<len;i++) a[i].SetValue(0,0);
}
void Readr(Complex y[]) {
for(int i = 1,j = len>>1;i<len-1;i++) {
if(i<j) swap(y[i],y[j]);
int k = len>>1;
while(j>=k) {
j -= k;
k>>=1;
}
if(j<k) j+=k;
}
}
void FFT(Complex y[],int op) {
Readr(y);
for(int h  = 2;h<=len;h<<=1) {
Complex wn(cos(2*Pi*op/h),sin(2*Pi*op/h));
for(int i = 0;i<len;i+=h) {
Complex w(1,0);
for(int j = i;j<i+h/2;j++) {
Complex u = y[j];
Complex v = w*y[j+h/2];
y[j] = u+v;
y[j+h/2] = u-v;
w = w*wn;
}
}
}
if(op == -1) {
for(int i = 0;i<len;i++) y[i].real/=len;
}
}
LL Convolution() {
FFT(a,1);
for(int i =0;i<len;i++) a[i] = a[i]*a[i];
FFT(a,-1);
LL ans = 0;
for(int i = 0;i < len;i++) sum[i] = (LL)(a[i].real+0.5);
for(int i = 0;i < n ; i++) sum[s[i]+s[i]]--;
for(int i = 0;i < len;i++) sum[i]/=2;
for(int i = 1;i < len;i++) sum[i] +=sum[i-1];
for(int i = 0;i<n;i++) {
ans+=sum[len-1]-sum[s[i]];
ans-=LL(n-1-i)*i;
ans-=(n-1);
ans-=LL(n-1-i)*(n-2-i)/2;
}
return ans;
}
int main() {
int T;
scanf("%d",&T);
while(T--) {
memset(num,0,sizeof(num));
scanf("%d",&n);
for(int i = 0;i<n;i++) {
scanf("%d",&s[i]);
num[s[i]]++;
}
sort(s,s+n);
len1 = s[n-1]+1;
Get();
LL p = Convolution();
LL q = 1LL*(n)*(n-1)*(n-2)/6;
printf("%.7f\n",p*1.0/q);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: