• [BZOJ3513] idiots


    Description

    给定 (n) 条边的长度,任选三条边(组合),求能组成三角形的概率。

    Solution

    首先预处理出任选两条边(可以重复且不限顺序)每种长度和 (i) 对应的方案数 (c[i]),这个很显然可以用 FFT 求出。

    考虑如何修正为组合数,对于每条边 (a_i),将 (c[2a_i]) 减去 (1),即去除将这条边重复选两次的情况。尔后,对所有 (c[i]) 除以 (2),即去除顺序。这样得到的 (c[i]) 就是选择两条不同的边,边长和为 (i) 的组合数。

    现考虑枚举最长边来计算答案,假设当前最长边为 (a_i),则对答案的贡献为

    [sum_{j=a_i+1}^{infty} c[i]-(i-1)(n-i)-frac{(n-i)(n-i-1)}{2}-(n-1) ]

    其中第二项为一大一小的方案数,第三项为两大的方案数,第四项为选重了该边的方案数。

    #include<bits/stdc++.h>
    #define N 262145
    #define pi acos(-1)
    using namespace std;
    
    #define int long long 
    
    namespace po {
    typedef complex<double> E;
    int n,m,L;
    int R[N];
    E a[N],b[N];
    
    void fft(E *a,int f){
    	for(int i=0;i<n;i++)if(i<R[i])swap(a[i],a[R[i]]);
    	for(int i=1;i<n;i<<=1){
    		E wn(cos(pi/i),f*sin(pi/i));
    		for(int p=i<<1,j=0;j<n;j+=p){
    			E w(1,0);
    			for(int k=0;k<i;k++,w*=wn){
    				E x=a[j+k],y=w*a[j+k+i];
    				a[j+k]=x+y;a[j+k+i]=x-y;
    			}
    		}
    	}
    }
    
    void mul(int _n,int *aa,int *bb,int *cc){
        n=_n;
        memset(a,0,sizeof a);
        memset(b,0,sizeof b);
        memset(R,0,sizeof R);
        L=0;
        m=n;
    	for(int i=0,x;i<=n;i++)a[i]=aa[i];
    	for(int i=0,x;i<=m;i++)b[i]=bb[i];
    	m*=2;
    	for(n=1;n<=m;n<<=1)L++;
    	for(int i=0;i<n;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
    	fft(a,1);fft(b,1);
    	for(int i=0;i<=n;i++)a[i]=a[i]*b[i];
    	fft(a,-1);
    	memset(cc,0,sizeof cc);
    	for(int i=0;i<=m;i++) cc[i]=(int)(a[i].real()/n+0.5);
    }
    }
    
    using po::mul;
    
    int n,a[N],b[N],c[N],d[N];
    
    void solve()
    {
        cin>>n;
        memset(a,0,sizeof a);
        memset(b,0,sizeof b);
        memset(c,0,sizeof c);
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=1;i<=n;i++) b[a[i]]++;
        int m=*max_element(a+1,a+n+1);
        mul(m+1,b,b,c);
        m=(m+1)*2;
        for(int i=1;i<=n;i++) c[2*a[i]]--;
        for(int i=0;i<=m;i++) c[i]/=2;
        for(int i=m;i>=0;--i) c[i]+=c[i+1];
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            ans+=c[a[i]+1];
            ans-=(i-1)*(n-i);
            ans-=(n-i)*(n-i-1)/2;
            ans-=n-1;
        }
        printf("%.7lf
    ",1.0*ans/n/(n-1)/(n-2)*6);
    }
    
    signed main()
    {
        ios::sync_with_stdio(false);
    
        int t;
        cin>>t;
        while(t--)
        {
            solve();
        }
    
        return 0;
    }
    
    /*
    2 
    4 
    1 3 3 4 
    4 
    2 3 3 4
    */
    
  • 相关阅读:
    整理用js实现tab标签页
    整理悬浮在列表中a元素时改变a元素上下边框颜色的问题。
    整理Javascript基础数据和引用数据复制值的问题
    这一周的学习整理
    关于变量作用域的一点整理
    Javascript 知识遗漏点梳理。
    安卓自定义TextView实现自动滚动
    解决 IntelliJ IDEA Tomcat 控制台中文输出乱码问题
    Tomcat 控制台UTF-8乱码问题
    java 实现hex文件转换bin保存至内存中
  • 原文地址:https://www.cnblogs.com/mollnn/p/13780399.html
Copyright © 2020-2023  润新知