[BZOJ3513] [MUTC2013] idiots [FFT/NTT]

Link
https://www.lydsy.com/JudgeOnline/problem.php?id=3513


实际上就是要求 a i + a j &lt; a k a_i+a_j&lt;a_k ai+aj<ak 其中 a i ≤ a k , a j ≤ a k a_i\le a_k,a_j\le a_k aiak,ajak
考虑 f ( x ) f(x) f(x) a i + a j = x a_i+a_j=x ai+aj=x 的方案数,再考虑 ≥ x \ge x x 的木棍有 g ( x ) g(x) g(x)
那么不合法的方案数为 ∑ x = 1 max ⁡ a i f ( x ) g ( x ) \sum\limits_{x=1}^{\max a_i}f(x)g(x) x=1maxaif(x)g(x)
再考虑 a ( x ) a(x) a(x) 表示有几根棍棍长度为 x x x
f ( x ) = 1 2 ∑ r = 1 x − 1 a ( r ) a ( x − r ) − [ 2 ∣ x ] ⋅ a ( x / 2 ) f(x)=\frac{1}{2}\sum\limits_{r=1}^{x-1}a(r)a(x-r)-[2|x]\cdot a(x/2) f(x)=21r=1x1a(r)a(xr)[2x]a(x/2)

我果然是大常数选手……卡线过题(


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<cctype>
#include<ctime>
using namespace std;
#define getchar() (frS==frT&&(frT=(frS=frBB)+fread(frBB,1,1<<12,stdin),frS==frT)?EOF:*frS++)
char frBB[1<<12], *frS=frBB, *frT=frBB;
const double api = 2.0 * acos(-1.0);
inline void read(int& x)
{
	x = 0; char ch = getchar(); bool w = 0;
	while (!isdigit(ch)) w |= (ch == '-'), ch = getchar();
	while (isdigit(ch)) x = x * 10 + (ch ^ 48), ch = getchar();
	w ? (x = -x) : 0;
}
const int MAXN = 282828;
int T, n, m, Lim = 1, Log = 0;
int Rev[MAXN];
struct Complex
{
	double r, i;
	inline Complex(const double& a = 0, const double& b = 0) { r = a, i = b;}
	inline Complex operator + (const Complex& o) { return Complex(r + o.r, i + o.i);}
	inline Complex operator - (const Complex& o) { return Complex(r - o.r, i - o.i);}
	inline Complex operator * (const Complex& o) { return Complex(r * o.r - i * o.i, r * o.i + i * o.r);}
	//下面三个不能写 const& 不然自乘可能会炸 
	inline void operator += (Complex o) { r += o.r, i += o.i;}
	inline void operator -= (Complex o) { r -= o.r, i -= o.i;}
	inline void operator *= (Complex o) { static double tr, ti; tr = r, ti = i; r = tr * o.r - ti * o.i, i = tr * o.i + ti * o.r;}
}a[MAXN], Wn[MAXN][2];
inline void FFT(Complex *a, const bool& Type = 0)
{
	for (register int i = 0; i < Lim; ++i) if (Rev[i] > i) swap(a[Rev[i]], a[i]);
	register Complex x;
	for (register int Mid = 1, Len, qwq; Mid < Lim; Mid <<= 1)
	{
		Len = Mid << 1;
		qwq = Lim / Len;
		for (register int Pos = 0; Pos < Lim; Pos += Len)
		{
			for (register int Sub = 0; Sub < Mid; ++Sub)
			{
				x = Wn[qwq * Sub][Type] * a[Pos + Mid + Sub];
				a[Pos + Mid + Sub] = a[Pos + Sub] - x;
				a[Pos + Sub] += x;
			}
		}
	}
}
long long F[MAXN], Total;
int G[MAXN], A[MAXN];
int main()
{
	read(T);
	while (T--)
	{
		read(n);
		memset(a, 0, sizeof(a));
		m = 0;
		for (register int tem, i = 1; i <= n; ++i)
		{
			read(tem);
			m = max(m, tem);
			++a[tem].r;
		}
		for (register int i = 1; i <= m; ++i) A[i] = int(a[i].r);
		G[m+1] = 0;
		for (register int i = m; i >= 1; --i) G[i] = G[i+1] + A[i];
		Lim = 1, Log = 0;
		int temtem = m<<1;
		while (Lim <= temtem) Lim <<= 1, ++Log;
		for (register int i = 0; i < Lim; ++i) Rev[i] = (Rev[i>>1]>>1)|((i&1)<<(Log-1));
		{
			const double tpi = api / Lim;
			register double tem = 0, cs, tm;
			for (register int i = 0; i < Lim; ++i) cs = cos(tem), tm = sin(tem), Wn[i][0] = Complex(cs, tm), Wn[i][1] = Complex(cs, -tm), tem += tpi; 
		}
		FFT(a);
		for (register int i = 0; i < Lim; ++i) a[i] *= a[i];
		FFT(a, 1);
		for (register int i = 2; i <= m; ++i) 
		{
			F[i] = (long long)(a[i].r / Lim + 0.5);
			if (!(i&1)) F[i] -= A[i>>1];
			F[i] >>= 1;
		}
		for (register int i = 1; i <= m; ++i) F[i] = F[i-1] + F[i] * G[i];
		Total = 1ll * n * (n-1) * (n-2) / 6;
		printf("%.7f\n", 1.0 * (Total - F[m]) / Total);
	}           
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值