HDU 4609 FFT

题意

传送门 HDU 4609 3-idiots

题解

N N N 个数中任取三个,求选择的数可以作为三角形边长的概率。对于三角形的判定条件,即 a i + a j > a k , a k ≥ a j , a i a_i+a_j>a_k, a_k\geq a_j,a_i ai+aj>ak,akaj,ai。计数时还需考虑所选择的数互不相同。

A ( x ) = ∑ x a i A(x)=\sum x^{a_i} A(x)=xai,简单起见写为 ∑ x \sum x x,根据容斥原理,考虑相同项的数量,可以得到 ( ∑ x ) 2 = ∑ x 2 + 2 ∑ x y (\sum x)^2 = \sum x^2 + 2\sum xy (x)2=x2+2xy [ x k ] ∑ x y [x^k]\sum xy [xk]xy 即选择两个不同数使之满足求和为 k k k 的方案数。最终减去不满足 i < j < k i<j<k i<j<k 的方案数即可,这样的方案包含了使 a a a 有序后索引大于等于 k k k 的方案。

#include <bits/stdc++.h>
using namespace std;
using cp = complex<double>;
constexpr double PI = acos(-1);
vector<int> rev;
vector<cp> omg, omgInv;
struct Poly : vector<cp>
{
    Poly() {}
    Poly(int n) : vector<cp>(n) {}
    Poly(const initializer_list<cp> &list) : vector<cp>(list) {}
    void fft(int n, bool inverse)
    {
        if ((int)rev.size() != n)
        {
            rev.resize(n);
            omg.resize(n);
            omgInv.resize(n);
            for (int i = 0; i < n; ++i)
            {
                rev[i] = rev[i >> 1] >> 1 | (i & 1 ? n >> 1 : 0);
                omg[i] = cp(cos(2 * PI * i / n), sin(2 * PI * i / n));
                omgInv[i] = conj(omg[i]);
            }
        }
        resize(n);
        for (int i = 0; i < n; ++i)
            if (i < rev[i])
                std::swap(at(i), at(rev[i]));

        for (int m = 1; m < n; m <<= 1)
        {
            int m2 = m << 1;
            for (int i = 0; i < n; i += m2)
                for (int j = 0; j < m; ++j)
                {
                    cp &x = at(i + j), &y = at(i + j + m);
                    cp t = (inverse ? omgInv[n / m2 * j] : omg[n / m2 * j]) * y;
                    y = x - t;
                    x += t;
                }
        }
    }
    void dft(int n) { fft(n, 0); };
    void idft(int n)
    {
        fft(n, 1);
        for (int i = 0; i < n; ++i)
            at(i) /= n;
    }
    Poly operator*(const Poly &p) const
    {
        auto a = *this, b = p;
        int k = 1, n = a.size() + b.size() - 1;
        while (k < n)
            k <<= 1;
        a.dft(k), b.dft(k);
        for (int i = 0; i < k; ++i)
            a[i] *= b[i];
        a.idft(k);
        a.resize(n);
        return a;
    }
};
using ll = long long;
constexpr int MAXN = 1E5 + 5;
int T, N, A[MAXN];
ll C[MAXN][4];

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    for (int i = 0; i < MAXN; ++i)
        C[i][0] = 1;
    for (int i = 1; i < MAXN; ++i)
        for (int j = 1; j <= 3; ++j)
            C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
    cin >> T;
    while (T--)
    {
        cin >> N;
        int amax = 0;
        for (int i = 0; i < N; ++i)
            cin >> A[i], amax = max(amax, A[i]);
        sort(A, A + N);
        Poly f(amax + 1);
        vector<int> a(amax + 1);
        for (int i = 0; i < N; ++i)
            ++a[A[i]];
        for (int i = 0; i <= amax; ++i)
            f[i].real(a[i]);
        f = f * f;
        int n = f.size();
        vector<ll> b(n);
        for (int i = 0; i < n; ++i)
            b[i] = floor(f[i].real() + 0.5);
        for (int i = 0; i < N; ++i)
            b[A[i] * 2]--;
        for (int i = 0; i < n; ++i)
            b[i] /= 2;
        vector<ll> sum(n);
        for (int i = 1; i < n; ++i)
            sum[i] = sum[i - 1] + b[i];
        ll res = 0;
        for (int i = N - 1; i >= 0; --i)
        {
            ll t = sum[n - 1] - sum[A[i]];
            t -= (ll)(i + N - 1) * (N - i) / 2;
            res += t;
        }
        cout << fixed << setprecision(7) << (double)res / C[N][3] << '\n';
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值