【题解】MUTC2013idiots

时间:2023-03-09 23:07:14
【题解】MUTC2013idiots

  我是先知道的这题是FFT然后再做的,知道是FFT其实就是个套路题啦。首先,我们容易发现

      \(P = \frac{a}{b}\) 其中a表示合法的方案数,而b表示全部的方案数。

  b的值即为\(C\left ( n,3 \right )\)。如何求出合法的方案数呢?先考虑一下:如果我们锁定最大的边,那么合法的方案数就是所有两根木棍长度之和大于这根木棍的方案数。可是这个不好求啊。因为如果要统计方案数,那就一要保证这根木棍不出现在统计的方案中,而要保证方案中出现的两根木棍长度均<=这根木棍的长度,但这是不好做到的(等于是每一根木棍条件不同,复杂度根本无法保证)。

  我们换一个角度:正难则反。不合法的方案数即为两根木棍之和<=这根木棍长度的方案数。这个是好求的,因为<=时,一定满足这根木棍是最长木棍&这根木棍与其他木棍组成的方案不会出现在其中。我们就可以用FFT快速求出卷积,算出两根木棍之和为x的方案数啦。

  可是这题我找了很多程序对拍没有问题,但bzoj上过不去……呜呜呜……所以就不放代码惹。

  ……还是放一下吧,如果有哪位小可爱知道我的程序出了什么问题万分感谢呀……(;д;)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define maxn 502000
#define int long long
#define db long double
const db Pi = acos(-1.0);
int T, n, L, S, LAST, len, ans, c[maxn];
int Rec[maxn], R[maxn], C[maxn];
int maxx; int read()
{
int x = ;
char c;
c = getchar();
while(c < '' || c > '') c = getchar();
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x;
} struct complex
{
db x, y;
complex (db xx = , db yy = ) { x = xx, y = yy; }
}g[maxn]; complex operator + (complex a, complex b) { return complex(a.x + b.x, a.y + b.y); }
complex operator - (complex a, complex b) { return complex(a.x - b.x, a.y - b.y); }
complex operator * (complex a, complex b) { return complex(a.x * b.x - a.y * b.y, (a.x * b.y + a.y * b.x)); } void FFT(complex *A, int opt)
{
for(int i = ; i < S; i ++)
if(i < R[i]) swap(A[i], A[R[i]]);
for(int mid = ; mid < S; mid <<= )
{
complex W(cos(Pi / mid), opt * sin(Pi / mid));
for(int r = mid << , j = ; j < S; j += r)
{
complex w(, );
for(int k = ; k < mid; k ++, w = w * W)
{
complex x = A[j + k], y = w * A[j + k + mid];
A[j + k] = x + y;
A[j + k + mid] = x - y;
}
}
}
} void init()
{
for(int i = ; i <= S; i ++)
g[i].x = g[i].y = ;
memset(Rec, , sizeof(Rec));
S = , maxx = , len = ans = ;
} void pre()
{
C[] = ;
for(int i = ; i < ; i ++)
C[i] = C[i - ] * i / (i - );
} signed main()
{
T = read();
pre();
while(T --)
{
init();
n = read();
for(int i = ; i <= n; i ++)
{
int x = read();
g[x].x += , Rec[x] += ;
maxx = max(x, maxx);
}
maxx *= ;
while(S <= maxx) S <<= , len ++;
for(int i = LAST; i < S; i ++)
R[i] = ((R[i >> ] >> ) | ((i & ) << (len - )));
LAST = max(LAST, S - );
FFT(g, );
for(int i = ; i < S; i ++) g[i] = g[i] * g[i];
FFT(g, -);
for(int i = ; i <= maxx; i ++) g[i].x /= S;
for(int i = ; i <= maxx; i ++)
{
int x = (int) (g[i].x + 0.5);
if(!(i % )) x -= Rec[i / ];
x /= ; g[i].x = x;
if(i != ) g[i].x += g[i - ].x;
}
for(int i = ; i <= maxx / ; i ++)
ans += ((int) g[i].x) * Rec[i];
printf("%.7Lf\n", (db) (C[n] - ans) / (db) C[n]);
}
return ;
}