HDU4609 3-idiots(母函数 + FFT)

题目

Source

http://acm.hdu.edu.cn/showproblem.php?pid=4609

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.

Input

An integer T(T≤100) will exist in the first line of input, indicating the number of test cases.
Each test case begins with the number of branches N(3≤N≤105).
The following line contains N integers a_i (1≤a_i≤105), which denotes the length of each branch, respectively.

Output

Output the probability that their branches can form a triangle, in accuracy of 7 decimal places.

Sample Input

2
4
1 3 3 4
4
2 3 3 4

Sample Output

0.5000000
1.0000000

分析

题目大概说,有n条边,长度在[1,100000],从中任选三条边,问组成三角形的概率是多少。

这题思路好绕。

详见:http://www.cnblogs.com/kuangbin/archive/2013/07/24/3210565.html

大概这样:

  • 首先求出两两组合成长度和位i的方案数tot[i]
  • 然后从小到大枚举三角形最长的边len,那么现在要确定另外两条边合法组合的方案数

这个方案数为:

Σtot[i](i>len)- 最长边与其他边组合的方案数 - 长度小于最长边与长度大于等于最长边的其他边组合的方案数 - 长度大于等于最长边的其他边之间组合的方案数

Σtot[i]可以通过前缀和差分求得,其他部分简单的组合计算。

而tot[i]如何求?

构造一个多项式,$\sum_ic_ix^i$,表示长度$i$的边有$c_i$个,而$\sum_ic_ix^i \times \sum_ic_ix^i$的结果$\sum_iC_ix^i$就表示有先后顺序且放回地选出两条边长度和为$i$的方案数为$C_i$

这其实是母函数吧。。然后利用FFT去快速求得这个多项式的值。

不过这个多项式求出来还不是最终的,再减去自身与自身组合,最后除以2即是要的tot[i]。

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAXN 277777
const double PI=acos(-1.0);

struct Complex{
	double real,imag;
	Complex(double _real,double _imag):real(_real),imag(_imag){}
	Complex(){}
	Complex operator+(const Complex &cp) const{
		return Complex(real+cp.real,imag+cp.imag);
	}
	Complex operator-(const Complex &cp) const{
		return Complex(real-cp.real,imag-cp.imag);
	}
	Complex operator*(const Complex &cp) const{
		return Complex(real*cp.real-imag*cp.imag,real*cp.imag+cp.real*imag);
	}
	void setValue(double _real=0,double _imag=0){
		real=_real; imag=_imag;
	}
};

int len;
Complex wn[MAXN],wn_anti[MAXN];

void FFT(Complex y[],int op){
	for(int i=1,j=len>>1,k; i<len-1; ++i){
		if(i<j) swap(y[i],y[j]);
		k=len>>1;
		while(j>=k){
			j-=k;
			k>>=1;
		}
		if(j<k) j+=k;
	}
	for(int h=2; h<=len; h<<=1){
		Complex Wn=(op==1?wn[h]:wn_anti[h]);
		for(int i=0; i<len; i+=h){
			Complex W(1,0);
			for(int j=i; j<i+(h>>1); ++j){
				Complex u=y[j],t=W*y[j+(h>>1)];
				y[j]=u+t;
				y[j+(h>>1)]=u-t;
				W=W*Wn;
			}
		}
	}
	if(op==-1){
		for(int i=0; i<len; ++i) y[i].real/=len;
	}
}
void Convolution(Complex A[],Complex B[],int n){
	for(len=1; len<(n<<1); len<<=1);
	for(int i=n; i<len; ++i){
		A[i].setValue();
		B[i].setValue();
	}
	for(int i=0; i<=len; ++i){
		wn[i].setValue(cos(2.0*PI/i),sin(2.0*PI/i));
		wn_anti[i].setValue(wn[i].real,-wn[i].imag);
	}
	FFT(A,1); FFT(B,1);
	for(int i=0; i<len; ++i){
		A[i]=A[i]*B[i];
	}
	FFT(A,-1);
}

Complex A[MAXN],B[MAXN];
int a[111111],cnt[111111];
long long tot[MAXN];
int main(){
	int t,n;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		memset(cnt,0,sizeof(cnt));
		int maxa=0;
		for(int i=0; i<n; ++i){
			scanf("%d",a+i);
			++cnt[a[i]];
			maxa=max(maxa,a[i]);
		}
		for(int i=0; i<=maxa; ++i){
			A[i].setValue(cnt[i]);
			B[i].setValue(cnt[i]);
		}
		Convolution(A,B,maxa+1);
		for(int i=0; i<len; ++i){
			tot[i]=(long long)(A[i].real+0.5);
		}
		for(int i=0; i<n; ++i){
			--tot[a[i]+a[i]];
		}
		for(int i=0; i<len; ++i){
			tot[i]>>=1;
		}
		for(int i=1; i<len; ++i){
			tot[i]+=tot[i-1];
		}
		sort(a,a+n);
		long long res=0;
		for(int i=0; i<n; ++i){
			long long tmp=tot[len-1]-tot[a[i]];
			tmp-=n-1; // 本身与其它的组合
			tmp-=(long long)i*(n-i-1); // 小于与大于等于的组合
			if(n-i-1>1) tmp-=(long long)(n-i-1)*(n-i-2)/2; // 大于等于之间的组合
			res+=tmp;
		}
		printf("%.7f\n",res*1.0/((long long)n*(n-1)*(n-2)/6));
	}
	return 0;
}
时间: 2024-08-06 04:55:16

HDU4609 3-idiots(母函数 + FFT)的相关文章

UVa12298 Super Poker II(母函数 + FFT)

题目 Source http://acm.hust.edu.cn/vjudge/problem/23590 Description I have a set of super poker cards, consisting of an infinite number of cards. For each positive composite integer p, there are exactly four cards whose value is p: Spade(S), Heart(H),

BZOJ 3771 Triple 母函数+FFT

题目大意:给定n个物品,可以用一个/两个/三个不同的物品凑出不同的价值,求每种价值有多少种拼凑方案(顺序不同算一种) 首先搞出这n个物品的母函数a 将a的每项的平方求和得到多项式b 将a的每项的立方求和得到多项式c 那么如果不考虑顺序和重复 那么方案数就是a+b+c 现在考虑顺序和重复后 三个物品的方案数为(a^3-3*a*b+2*c)/6 两个物品的方案数为(a^2-b)/2 一个物品的方案数为a 故最终答案为(a^3-3*a*b+2*c)/6+(a^2-b)/2+a 用FFT搞一下就好了-

[hdu4609]计数方法,FFT

题目:给一个数组a,从里面任选三个数,求以这三个数为三条边能构成三角形的概率. 思路:由于每个数只能用一次,所以考虑枚举三边中的最大边.先将a数组排序,然后枚举它的每个数x作为最大边,那么问题就是要求在数组a剩余的数里面“找小于等于x”且“和大于x”的数对个数,答案显然不能直接得到.不妨先计算这样一个数组ans[i]:表示在数组a里面有放回的选两个数,和为i的数对个数.设cnt[i]为i这个数在a数组里面出现的次数,那么ans相当于cnt对cnt的卷积结果, 这可以利用FFT在nlogn的时间内

[HDU4609] 3-idiots - 多项式乘法,FFT

题意:有\(n\)个正整数,求随机选取一个3组合,能构成三角形的概率. Solution: 很容易想到构造权值序列,对其卷积得到任取两条边(可重复)总长度为某数时的方案数序列,我们希望将它转化为两条边不可重复,并去掉顺序.不妨设给定的 \(N\) 个正整数的集合为 \(S\),卷积后的权值序列为 \(\{c_i\}\) ,那么我们对每一个 \(x \in S\), 对 \(c_x\) 减去 \(1\) 即可. 不妨设选出的组合为 \((i,j,k)\),假设 \({x_i}\) 为已经排序的长度

【自用】OI计划安排表一轮

网络流√ 上下界最大流√ 线性规划转费用流√ RMQ优化建图√ 单纯形√ 字符串相关 hash√ 扩展KMP 回文自己主动机 数据结构 平衡树 启示式合并 替罪羊树 LCT 树套树 KD-Tree 二分答案 分数规划√ 贪心 动态规划 斜率优化√ 数位DP√ 概率DP√ 插头DP 图论 差分约束√ floyd求最小环√ 连通分量相关√ 强连通分量√ 点双连通分量√ 边双连通分量√ 割点√ 割边√ 最小生成树√ Matrix-Tree定理√ 斯坦纳树√ 最小树形图√ 树上问题 Prufer序列 认

【自用】OI知识点总结

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/45216967"); } 看目录就好了.不用看具体部分 网络流 二分图 最大匹配 最小点覆盖 最小边覆盖 最小路径覆盖 最大独立集 最大流 上下界最大流 最小割 全局最小割 费用流 上下界费用流 线性规划转费用流 最大权闭合图 RMQ

「刷题」Triple

正解是指数型母函数+FFT. 才学了多项式,做了一道比较好的题了. 首先有三个斧子被偷了. 我们考虑构造一种指数型母函数. 就是说一种多项式吧,我的理解. 系数是方案,下标,也就是所谓的元指数代表的是价值. 这样如果两个母函数相乘的话,指数相加,系数相乘. 正好就是两个单元合并之后的方案和价值. $A(x),B(x),C(x)$分别代表一把相同的斧子用价值为x,2把为x,3把为x的方案数. 容斥一下. 三把的答案就是$A(x)*A(x)*A(x)-C_3^1A(x)B(x)+2C(x)$ 解释一

HDU4609 &amp; FFT

关于这道题请移步kuangbin爷的blog:http://www.cnblogs.com/kuangbin/archive/2013/07/24/3210565.html 感觉我一辈子也不能写出这么详细的题解. Code: /*================================= # Created time: 2016-04-18 16:03 # Filename: hdu4609.cpp # Description: =============================

bzoj 3513: [MUTC2013]idiots -- FFT

3513: [MUTC2013]idiots Time Limit: 20 Sec  Memory Limit: 128 MB Description 给定n个长度分别为a_i的木棒,问随机选择3个木棒能够拼成三角形的概率. Input 第一行T(T<=100),表示数据组数. 接下来若干行描述T组数据,每组数据第一行是n,接下来一行有n个数表示a_i. 3≤N≤10^5,1≤a_i≤10^5 Output T行,每行一个整数,四舍五入保留7位小数. Sample Input 2 4 1 3 3