[BZOJ 3513&HDU 4609][MUTC2013]idiots(FFT)

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.

Solution

题意就是给出一些长度问有多少种方案可以组成三角形

看到数据范围可以想到FFT

res[i]存两边之和为i的方案数(已除去同一条边选两次的情况并且/2),处理一个res[]的前缀和

排序之后,对于每一条边加上两边之和大于它的方案数,还需要减掉一些奇奇怪怪的东西…(因为这可能不是最长边)【分类讨论战零渣…

它们分别是:

1.n-1 选了这条边和另一条边的

2.i*(n-i-1) 选了小于它的一条边和大于它的一条

3.(n-i-1)*(n-i-2)/2 选了大于它的两条边

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define MAXN 100005
#define PI acos(-1)
using namespace std;
int T,n,a[MAXN],num[MAXN];
long long res[MAXN*4],sum[MAXN*4];
struct cp
{
    double r,i;
    cp(double r=0,double i=0):r(r),i(i){}
    cp operator + (const cp& A)
    {return cp(r+A.r,i+A.i);}
    cp operator - (const cp& A)
    {return cp(r-A.r,i-A.i);}
    cp operator * (const cp& A)
    {return cp(r*A.r-i*A.i,r*A.i+i*A.r);}
}x[MAXN*4];
void brc(cp* x,int l)
{
    int j=l/2;
    for(int i=1;i<l-1;i++)
    {
        if(i<j)swap(x[i],x[j]);
        int k=l/2;
        while(j>=k)
        {
            j-=k;
            k>>=1;
        }
        if(j<k)j+=k;
    }
}
void fft(cp* x,int l,int on)
{
    brc(x,l);
    for(int h=2;h<=l;h<<=1)
    {
        cp wn=cp(cos(2*on*PI/h),sin(2*on*PI/h));
        for(int j=0;j<l;j+=h)
        {
            cp w=cp(1,0);
            for(int k=j;k<j+h/2;k++)
            {
                cp u=x[k];
                cp t=w*x[k+h/2];
                x[k]=u+t;
                x[k+h/2]=u-t;
                w=w*wn;
            }
        }
    }
    if(on==-1)for(int i=0;i<l;i++)x[i].r/=l;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        memset(num,0,sizeof(num));
        int l1=0,l2=1;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            if(a[i]>l1)l1=a[i];
            num[a[i]]++;
        }
        l1++;
        for(int i=0;i<l1;i++)x[i]=cp(num[i],0);
        while(l2<l1*2)l2<<=1;
        for(int i=l1;i<l2;i++)x[i]=cp(0,0);
        fft(x,l2,1);
        for(int i=0;i<l2;i++)x[i]=x[i]*x[i];
        fft(x,l2,-1);
        for(int i=0;i<l2;i++)
        res[i]=(long long)(x[i].r+0.5);
        for(int i=0;i<n;i++)res[a[i]+a[i]]--;
        for(int i=0;i<l2;i++)res[i]/=2;
        sum[0]=res[0];
        for(int i=1;i<l2;i++)sum[i]=sum[i-1]+res[i];
        long long ans=0;
        sort(a,a+n);
        for(int i=0;i<n;i++)
        {
            ans+=sum[l2-1]-sum[a[i]];
            ans-=n-1;
            ans-=1LL*i*(n-i-1);
            ans-=1LL*(n-i-1)*(n-i-2)/2;
        }
        long long x=1LL*n*(n-1)*(n-2)/6;
        printf("%.7lf\n",(double)ans/x); 
    }
    return 0;
} 

 

posted @ 2017-04-17 22:40  Zars19  阅读(265)  评论(0编辑  收藏  举报