bzoj千题计划168:bzoj3513: [MUTC2013]idiots
http://www.lydsy.com/JudgeOnline/problem.php?id=3513
组成三角形的条件:a+b>c
其中,a<c,b<c
若已知
两条线段之和=i 的方案数g[i]
线段长度>i的 线段数量 t[i]
答案是否可以表示为 Σ g[i]*t[i] ?
不能,因为 有c是最大的数的限制
去掉c是最大数的限制:
不能组成三角形的条件:a+b<=c
其中,a<c,b<c
在这里,满足条件的c一定是abc中最大的
所以解题思路是 求出不能组成三角形的方案数S
g[i] 两条线段和为i的方案数
t[i] 线段长度>=i的 线段数
f[i] 线段长度=i的线段数
那么
g的计算:
g[i]= Σ f[j]*f[i-j]
若 i是偶数 g[i]-=f[i/2] (总长为i,方案数应该是f[i/2]*(f[i/2]-1),在式子中算的是f[i/2]*f[i/2])
g[i]/=2 (每个方案被枚举了两次)
S=Σg[i]*t[i]
tot=C(n,3)
ans=(tot-S)/ tot
用fft 把g的计算优化到 nlogn
多项式:g[]=f[]*f[]
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N=1<<18; const double pi=acos(-1); struct Complex { double x,y; Complex() { } Complex(double x_,double y_) : x(x_),y(y_) { } Complex operator + (Complex P) { Complex C; C.x=x+P.x; C.y=y+P.y; return C; } Complex operator - (Complex P) { Complex C; C.x=x-P.x; C.y=y-P.y; return C; } Complex operator * (Complex P) { Complex C; C.x=x*P.x-y*P.y; C.y=x*P.y+y*P.x; return C; } }; typedef Complex E; E f[N]; long long t[N],g[N]; int n; int r[N]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void fft(E *a,int tag) { 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),tag*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=w*wn) { E x=a[j+k],y=w*a[j+k+i]; a[j+k]=x+y; a[j+k+i]=x-y; } } } } int main() { int T; read(T); int a,mx; long long ans,tot; while(T--) { memset(t,0,sizeof(t)); memset(g,0,sizeof(g)); memset(f,0,sizeof(f)); read(n); tot=(long long)n*(n-1)*(n-2)/6; mx=0; for(int i=1;i<=n;++i) { read(a); t[a]++; f[a].x++; g[a<<1]--; mx=max(mx,a); } for(int i=mx-1;i;--i) t[i]+=t[i+1]; int m=mx-1<<1; int bit=0; for(n=1;n<=m;n<<=1) bit++; for(int i=0;i<n;++i) r[i]=(r[i>>1]>>1)|((i&1)<<bit-1); fft(f,1); for(int i=0;i<n;++i) f[i]=f[i]*f[i]; fft(f,-1); for(int i=0;i<n;++i) g[i]+=(int)(f[i].x/n+0.5); ans=0; for(int i=0;i<n;++i) ans+=(g[i]>>1)*t[i]; ans=tot-ans; printf("%.7lf\n",ans*1.0/tot); } }
3513: [MUTC2013]idiots
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 613 Solved: 219
[Submit][Status][Discuss]
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 4
4
2 3 3 4
4
1 3 3 4
4
2 3 3 4
Sample Output
0.5000000
1.0000000
1.0000000
HINT
T<=20
N<=100000