HDU 4609 3-idiots 解题报告

来源:互联网 发布:web 3d引擎 python 编辑:程序博客网 时间:2024/06/03 18:31

题目

2013 多校训练 第一场

题意:

有10^5条边,任选三条能组成三角形的概率?

题解:

因为边很多,所以要用FFT。

将边长变换后,对应元素自乘,再逆变换,就可以得到所有两条边和的方案数。但是由于同一条边可能选两次,所以要去掉这种情况。

用一个pre[i]来记两条边和大于i的方案数,枚举三角形的最长边,那么另外两条边的和必须比它大,但是这样算出来的方案数还包括了最长边也在另外两条边、最长边可能比另外两条边短的情况,所以要去掉。


代码写得好挫啊好挫啊……

//Time:2671ms//Memory:8952KB//Length:1788B#include <iostream>#include <cstdio>#include <cmath>#include <complex>#include <cstring>#define MAXN (4+(1<<18))using namespace std;typedef complex<long double> cmplx;const double PI = acos(-1.0);void FFT(cmplx y[],int n,double z){    for(int i(1),j(0); i<n; ++i)    {        for(int k=n>>1; k>(j^=k); k>>=1);        if(i<j) swap(y[i],y[j]);    }    for(int h(2); h<=n; h<<=1)    {        cmplx wn = exp(cmplx(0,z*2*PI/h));        for(int j(0); j<n; j+=h)        {            cmplx w(1,0);            for(int k(j); k<j+h/2; ++k)            {                cmplx u = y[k], t = w*y[k+h/2];                y[k] = u+t;                y[k+h/2] = u-t;                w*=wn;            }        }    }    if(z<0) for(int i(0); i<n; ++i) y[i]/=n;}int len[MAXN];double pre[MAXN];cmplx sum[MAXN];int main(){    //freopen("H:\\MyDocument\\Code\\input.txt","r",stdin);    int ncase,n,nn,mlen;    double ans;    scanf("%d",&ncase);    while(ncase--)    {        mlen=0;        scanf("%d",&n);        memset(sum,0,sizeof(sum));        for(int i=0;i<n;++i)            scanf("%d",&len[i]),sum[len[i]]+=1,mlen=max(mlen,len[i]);        nn=1;        mlen*=2;        while(nn<=mlen) nn<<=1;        FFT(sum,nn,1);        for(int i=0;i<=nn;++i)   sum[i]*=sum[i];        FFT(sum,nn,-1);        ans=0;        for(int i=0;i<n;++i)  sum[len[i]*2]-=1;        pre[0]=sum[0].real();        for(int i=1;i<=nn;++i)            pre[i]=pre[i-1]+sum[i].real();        for(int i=0;i<n;++i)        {            ans+=(pre[nn]-pre[len[i]])/2;            ans-=(long long)(n-i-1)*i+(n-1)+(long long)(n-i-1)*(n-i-2)/2;        }        printf("%.7f\n",ans/n/(n-1)/(n-2)*6);    }    return 0;}


原创粉丝点击