• [HDU4609] 3-idiots


    题意:有(n)个正整数,求随机选取一个3组合,能构成三角形的概率。

    Solution: 很容易想到构造权值序列,对其卷积得到任取两条边(可重复)总长度为某数时的方案数序列,我们希望将它转化为两条边不可重复,并去掉顺序。不妨设给定的 (N) 个正整数的集合为 (S),卷积后的权值序列为 ({c_i}) ,那么我们对每一个 (x in S), 对 (c_x) 减去 (1) 即可。

    不妨设选出的组合为 ((i,j,k)),假设 ({x_i}) 为已经排序的长度序列,那么我们不妨枚举最长边下标 (k),那么这一次的贡献为

    [sum_{k in S}(sum_{i=k+1}^{infty}{c_i}) ]

    前缀和扫一遍即可。当然问题并没有这么简单,我们这样获得的答案无法满足下列约束条件

    [k geq i, k geq j, i eq k, j eq k ]

    如果所有数字都不同,那么去重将是非常容易的。我们对排序后序列枚举元素下标 (i in [0,n)),那么很显然以 (i) 为最大边时非法的共有三类。不妨设(a_i<a_j)

    满足(a_i>a_k, a_j>a_k)的共有

    [frac{(n-i-1)(n-i-2)}{2} ]

    满足(a_i<a_k, a_j>a_k)的共有

    [(n-i-1)i ]

    满足(a_i=a_k or a_j=a_k)的共有

    [n-1 ]

    于是我们暴力统计一遍就可以得到非法数量,进而得出答案。

    原问题是可以出现相同大小的数字的,但容易发现它的去重情况与全部不相同并没有什么差异。因而直接按照上述做法即可得出答案。

    我们也可以对这个转化的正确性稍作证明。我们将原始序列中的每一个元素 (x_i) 映射到一个新元素

    [y_i = x_i - 0.2 + 0.1 cdot frac{i}{n} ]

    容易证明(x_i,x_j,x_k)可以构成三角形当且仅当(y_i,y_j,y_k)可以构成三角形。因此我们通过构造说明了这个转化的正确性。

    笔者菜甚,尝试用前缀和直接求解带重复情况失败,留坑在此。

    const int N = 200005;
    int T,n,m,x[N],a[N],s[N];
    double c[N];
    double t[N];
    
    int main() {
    	ios::sync_with_stdio(false);
    	cin>>T;
    	while(T--) {
    		cin>>n;
    		memset(a,0,sizeof a);
    		memset(x,0,sizeof x);
    		memset(s,0,sizeof s);
    		memset(c,0,sizeof c);
    		memset(t,0,sizeof t);
    		for(int i=0;i<n;i++) cin>>x[i];
    		for(int i=0;i<n;i++) m=max(x[i],m);
    		for(int i=0;i<n;i++) a[x[i]]++;
    		poly p,q;
    		p.c.resize(m+1);
    		for(int i=0;i<=m;i++) p.c[i]=a[i];
    		q=p;
    		double ans = 0;
    		p*=q;
    		for(int i=0;i<=2*m;i++) c[i]=(p.c[i]);
    		for(int i=0;i<n;i++) c[x[i]*2]-=1;
    		for(int i=0;i<=2*m;i++) c[i]/=2.0;
    		t[0]=c[0];
    		for(int i=1;i<=2*m;i++) t[i]=t[i-1]+c[i];
    		for(int i=0;i<n;i++) ans+=(t[2*m]-t[x[i]]);
    		sort(x,x+n);
    		for(int i=0;i<n;i++) {
    			ans -= (long long)(n-i-1)*(long long)(n-i-2)/2 + (long long)(n-i-1)*(long long)i + (n-1);
    		}
    		printf("%.7f
    ",6.0*(double)ans / ((double)n*(n-1.0)*(n-2.0)));
    	}
    }
    
  • 相关阅读:
    新式类、经典类与多继承
    实现抽象类之方式二
    实现抽象类之方式一
    re模块
    28个高频Linux命令
    Git使用教程
    编程语言介绍
    编码
    进制
    操作系统简史
  • 原文地址:https://www.cnblogs.com/mollnn/p/11637945.html
Copyright © 2020-2023  润新知