链接
http://acm.hdu.edu.cn/showproblem.php?pid=4609
题解
我发现凡是涉及到精度的题目,就会让人有一种"会不会是因为精度导致了
W
A
\color{red}WA
WA"的疑虑,其实如果认为自己的算法没问题的话,可以适当打消这种疑虑,否则会影响的速度,赛场上是有消极影响的
我先搞一个“桶”,统计每种数字的出现次数
c
n
t
i
cnt_i
cnti,把
c
n
t
cnt
cnt数组看作一个多项式的系数向量,进行多项式卷积
然后就得到了每种权值可以由多少种组合得到(减去重复的情况),设其为
c
n
t
2
i
cnt2_i
cnt2i
然后枚举最大边
c
c
c
现在我就是要统计,有多少种选法,使得最大边为
c
c
c,且较小的两条边
a
,
b
a,b
a,b满足
a
+
b
>
c
a+b>c
a+b>c
容易发现
a
>
0
,
b
>
0
a>0,b>0
a>0,b>0所以当
a
,
b
≤
c
a,b\leq c
a,b≤c时会有很好的性质“
a
<
c
a<c
a<c且
b
<
c
b<c
b<c”,但是当
a
+
b
>
c
a+b>c
a+b>c时却容易把“
a
>
c
a>c
a>c或
b
>
c
b>c
b>c”的情况给统计进去,所以我可以容斥一下,去统计
a
,
b
≤
c
a,b\leq c
a,b≤c的情况,最后再用总数减去
显然
a
,
b
≤
c
a,b\leq c
a,b≤c且
a
≤
c
,
b
≤
c
a\leq c,b\leq c
a≤c,b≤c的数量就等于
∑
i
=
1
c
c
n
t
2
i
\sum_{i=1}^ccnt2_i
∑i=1ccnt2i
而
a
,
b
≤
c
a,b\leq c
a,b≤c的选择方法数,可以分三种情况累加:
不妨设
c
c
c有
x
x
x个
情况一:选择三个
c
c
c,
C
x
3
C_{x}^3
Cx3
情况二:选两个
c
c
c,
C
x
2
∑
i
=
1
c
−
1
c
n
t
i
C_{x}^2\sum_{i=1}^{c-1}cnt_i
Cx2∑i=1c−1cnti
情况三:选一个
c
c
c,
C
x
1
∑
i
=
1
c
−
1
(
c
n
t
i
)
(
(
∑
i
=
1
c
−
1
c
n
t
i
)
−
1
)
2
C_{x}^1\frac{\sum_{i=1}^{c-1}(cnt_i)((\sum_{i=1}^{c-1}cnt_i)-1)}{2}
Cx12∑i=1c−1(cnti)((∑i=1c−1cnti)−1)
代码
#include <bits/stdc++.h>
#define maxn 300010
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
struct comp
{
double x, y;
comp(double x, double y):x(x),y(y){}
comp():x(0),y(0){}
comp operator+(comp t){return comp(x+t.x, y+t.y);}
comp operator-(comp t){return comp(x-t.x, y-t.y);}
comp operator*(comp t){return comp(x*t.x-y*t.y, x*t.y+t.x*y);}
}a[maxn], b[maxn], c[maxn];
struct FFT
{
int up, R[maxn];
const double pi=acos(-1);
void init(int bound) //bound是积多项式的最高次幂
{
int L(0);
for(up=1;up<=bound;up<<=1,L++);
for(int i=0;i<up;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
}
void fft(comp* a, int opt)
{
int i, j, k;
comp wn, w, x, y;
for(i=0;i<up;i++)if(i>R[i])swap(a[i],a[R[i]]);
for(i=1;i<up;i<<=1)
{
wn=comp(cos(pi/i),opt*sin(pi/i));
for(j=0;j<up;j+=i<<1)
for(w=comp(1,0),k=0;k<i;k++,w=w*wn)
{
x=a[k+j], y=a[k+j+i]*w;
a[k+j]=x+y, a[k+j+i]=x-y;
}
}
if(opt==-1)for(i=0;i<up;i++)a[i].x/=up;
}
void juan(comp* a, comp* b, comp* c)
{
fft(a,1), fft(b,1);
for(int i=0;i<up;i++)c[i]=a[i]*b[i];
fft(c,-1);
}
}fft;
ll read(ll x=0)
{
ll c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-48;
return f*x;
}
ll cnt[maxn], cnt2[maxn];
int main()
{
ll T(read()), N, i, j, ans, mx;
while(T--)
{
cl(cnt), cl(cnt2), cl(a), cl(b), cl(c), ans=0, mx=0;
N=read();
for(i=1;i<=N;i++)
{
auto x=read();
mx=max(mx,x);
cnt[x]++;
}
for(i=1;i<=mx;i++)a[i].x=cnt[i], b[i]=a[i];
fft.init(mx*2);
fft.juan(a,b,c);
for(i=1;i<=mx;i++)c[2*i].x-=cnt[i];
for(i=1;i<=mx;i++)cnt2[i]=ll(c[i].x+0.5)/2;
for(i=1;i<=mx;i++)cnt[i]+=cnt[i-1], cnt2[i]+=cnt2[i-1];
for(i=1;i<=mx;i++)
{
auto x=cnt[i]-cnt[i-1];
ans += x*cnt[i-1]*(cnt[i-1]-1)/2 + x*(x-1)/2*cnt[i-1] + x*(x-1)*(x-2)/6;
ans -= cnt2[i]*x;
}
printf("%.7lf\n",double(6*ans)/(N*(N-1)*(N-2)));
}
return 0;
}