• HDU#4609. 3-idiots



    题目大意:

    给定n个长度为ai的木棍
    求,任选三个使其能够组成三角形的概率



    分析:

    ai <= 1e5,先统计c[i]代表长度为i的木棍有多少个
    对c做卷积,即使用FFT求出 rep(i,0,1e5) rep(j,0,1e5) d[i+j]+=c[i]*c[j] 的d数组
    d[i]即代表选出两个木棍长度之和为i的方案数
    去除重复,减去使用了同一木棍两次的,i+j与j+i应为同一方案,所以rep(i,0,2e5) d[i]/=2
    现在d[i]已经可以表示选出两个不同木棍长度之和为i的不同方案数了

    接下来对木棍长度ai从小到大排序,对d做前缀和sd
    枚举最长边为第i根木棍,则另外两条边长度之和>ai,ans+=sd[2e5]-sd[ai]
    这些方案里需要去除一些不满足要求(ai为最长边)的
    1.另外两条边两条均>ai,ans-=(n-i)*(n-i-1)/2
    2.另外两条边一条>ai,一条<ai,ans-=(n-i)*(i-1)
    3.另外两条边一条=ai,另一条随意,ans-=n-1


    附上代码:

    /*     ai <= 1e5,先统计c[i]代表长度为i的木棍有多少个
         对c做卷积,即使用FFT求出 rep(i,0,1e5) rep(j,0,1e5) d[i+j]+=c[i]*c[j] 的d数组
         d[i]即代表选出两个木棍长度之和为i的方案数
         去除重复,减去使用了同一木棍两次的,i+j与j+i应为同一方案,所以rep(i,0,2e5) d[i]/=2
         现在d[i]已经可以表示选出两个不同木棍长度之和为i的不同方案数了
     
         接下来对木棍长度ai从小到大排序,对d做前缀和sd
         枚举最长边为第i根木棍,则另外两条边长度之和>ai,ans+=sd[2e5]-sd[ai]
         这些方案里需要去除一些不满足要求(ai为最长边)的
         1.另外两条边两条均>ai,ans-=(n-i)*(n-i-1)/2
         2.另外两条边一条>ai,一条<ai,ans-=(n-i)*(i-1)
         3.另外两条边一条=ai,另一条随意,ans-=n-1*/
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=4e5+12;
    const double pi=acos(-1);
    int n,N;
    long long num[maxn],branch[maxn];
    
    struct Complex
    {
        double x,i;
        Complex(){}
        Complex(double a,double b) {x=a;i=b;}
    }A[maxn];
    Complex operator + (Complex a,Complex b) {return Complex(a.x+b.x,a.i+b.i);}
    Complex operator - (Complex a,Complex b) {return Complex(a.x-b.x,a.i-b.i);}
    Complex operator * (Complex a,Complex b) {return Complex(a.x*b.x-a.i*b.i,a.x*b.i+a.i*b.x);}
    
    int rev[maxn];
    void FFT(Complex *a,int t)
    {
        for(int i=0;i<n;i++) if(rev[i]>i) swap(a[i],a[rev[i]]);
    
        for(int i=1;i<n;i<<=1)
        {
            Complex wn(cos(2*pi/(i<<1)),t*sin(2*pi/(i<<1)));
            for(int j=0;j<n;j+=(i<<1))
            {
                Complex w(1,0),t0,t1;
                for(int k=0;k<i;k++) 
                {
                    t0=a[j+k];t1=w*a[i+j+k];
                    a[j+k]=t0+t1;
                    a[i+j+k]=t0-t1;
                    w=w*wn;
                }
            }
        }
    }
    long long sum[maxn];
    int main()
    {
        freopen("a.in","r",stdin);
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&N);
            memset(num,0,sizeof(num));
            for(int i=0;i<N;i++) scanf("%d",&branch[i]),num[branch[i]]++;
            sort(branch,branch+N);//从小到大排序 
            
            int imax=branch[N-1]+1;//最大的数     
            n=1;int len=0;//n为2的len次方 n要比2*imax-1大 避免冲突 
            while(n<imax*2) n<<=1,len++;//两个imax相乘 会更新2*imax的位置 
            
            for(int i=0;i<imax;i++) A[i]=Complex(num[i],0);// 
            for(int i=imax;i<n;i++) A[i]=Complex(0,0);
            
            rev[0]=0;
            for(int i=1;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(len-1));//len是要他们的二进制长度+1 
        
            FFT(A,1);
        
            for(int i=0;i<n;i++) A[i]=A[i]*A[i];//卷积 
            FFT(A,-1);
            
            for(int i=0;i<n;i++) num[i]=(long long)(A[i].x/n+0.5);//求出num 
            imax=2*branch[N-1];//最大的和为imax  
            for(int i=0;i<N;i++) num[branch[i]*2]--;//把自己和自己的组成的都减去 
            for(int i=1;i<=imax;i++) num[i]/=2;//1 2与2 1我们计算了两次 所有整体除二 
            sum[0]=0;
            for(int i=1;i<=imax;i++) sum[i]=sum[i-1]+num[i];
            
            long long cnt=0;
            for(int i=0;i<N;i++) 
            {
                cnt+=sum[imax]-sum[branch[i]];
                //减掉一个取大,一个取小的
                cnt-=(long long)(N-1-i)*i;
                //减掉一个取本身,另外一个取其它
                cnt-=(N-1);
                //减掉大于它的取两个的组合
                cnt-=(long long)(N-1-i)*(N-i-2)/2;
            }
            long long tot = (long long)N*(N-1)*(N-2)/6;
            printf("%.7lf
    ",(double)cnt/tot);
        }
        return 0;
    }
    View Code

  • 相关阅读:
    win10 uwp 弹起键盘不隐藏界面元素
    win10 uwp 存放网络图片到本地
    win10 uwp 存放网络图片到本地
    sublime Text 正则替换
    sublime Text 正则替换
    win10 uwp 绘图 Line 控件使用
    win10 uwp 绘图 Line 控件使用
    AJAX 是什么?
    什么是 PHP SimpleXML?
    PHP XML DOM:DOM 是什么?
  • 原文地址:https://www.cnblogs.com/Heey/p/9055495.html
Copyright © 2020-2023  润新知