【BZOJ3513】idiots

DarkBZOJ https://darkbzoj.tk/problem/3513


Solution

也就是要求两边之和大于第三边

[a_x+a_y>a_k ]

记大于 (c)(a_x+a_y)(s_c) 个,等于 (c)(a_k)(b_c)
那么要求的就是

[sumlimits_{c=1}^{mx_a}s_cb_c ]

这不就完了?……其实不行,因为这并没有保证 (a_x e a_k)(a_y e a_k)
那怎么办呢,

其实反过来就好了,不要记大于的,记小于等于的……。然后排除。
444
于是现在剩下要做的事情就是,怎么把 (s_c) 求出来
双指针是不行的,(O(n^2))
然后 (a_i) 级别比较小,可以开桶,仔细一想
明显就是一个卷积了

传统艺能:复数四则运算打错。。
另外最后忘记再反回去了,直接写了个 ans / tot
实际上是 (tot - ans) / tot

最后统计的时候各种各样的求和不要写错哦(


Code

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cctype>
using namespace std;
const int maxn = 5e5;
const int maxv = 2e5;
const double tpi = acos(-1.0);
int n_T, n, a[maxn], lim = 0, lgl, rev[maxn], mx;
long long tp[maxn], tb[maxn], tg[maxn];
long long ans;
struct cp
{
    double r, i;
    cp (double a = 0, double b = 0) { r = a, i = b; }
    cp operator + (cp b) { return cp(r + b.r, i + b.i); }
    cp operator - (cp b) { return cp(r - b.r, i - b.i); }
    cp operator * (cp b) { return cp(r * b.r - i * b.i, r * b.i + i * b.r); }
    void operator *= (cp b) { *this = *this * b; }
    void operator += (cp b) { r += b.r, i += b.i; }
    void operator -= (cp b) { r -= b.r, i -= b.i; }
} w, wn, t, b[maxn];
void fft(cp *a, int opt)
{
    for (int i = 0; i < lim; ++i) if (i < rev[i]) swap(a[i], a[rev[i]]);
    for (int len, half = 1; half < lim; half = len)
    {
        len = half << 1;
        wn = cp(cos(tpi / half), sin(tpi / half) * opt);
        for (int pos = 0; pos < lim; pos += len)
        {
            w = cp(1, 0);
            for (int k = 0; k < half; ++k, w *= wn)
            {
                t = w * a[pos + half + k];
                a[pos + half + k] = a[pos + k] - t;
                a[pos + k] += t;
            }
        }
    }
    if (opt == -1) { for (int i = 0; i < lim; ++i) a[i].r /= lim; }
}
int main()
{
    cin >> n_T;
    while (n_T--)
    {
        for (int i = 0; i < lim; ++i)
        {
            b[i].r = 0;
            b[i].i = 0;
            tb[i] = 0;
        }
        cin >> n;
        lim = 1, lgl = mx = 0;
        for (int i = 1; i <= n; ++i)
        {
            cin >> a[i];
            ++b[a[i]].r;
            ++tb[a[i]];
            if (a[i] > mx) mx = a[i];
        }
        mx <<= 1;
        while (lim <= mx) lim <<= 1, ++lgl;
        for (int i = 0; i < lim; ++i) 
        {
            rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lgl - 1));
        }
        fft(b, +1);
        for (int i = 0; i < lim; ++i) 
        {
            b[i] *= b[i];
        }
        fft(b, -1);
        for (int i = 2; i <= mx; ++i)
        {
            tp[i] = ((long long)(b[i].r + 0.5));
            if (!(i & 1)) tp[i] -= tb[i >> 1];
            tp[i] >>= 1;
        }
        ans = 0;
        tg[mx + 1] = 0;
        for (int i = mx; i >= 0; --i)
        {
            tg[i] = tg[i + 1] + tb[i];
        }
        for (int i = 2; i <= mx; ++i)
        {
            ans += tp[i] * tg[i];
        }
        long long tot = 1ll * n * (n - 1) * (n - 2) / 6;
        printf("%.7f
", 1.0 * (tot - ans) / tot);
    }
    // system("pause"); 
    return 0;
}
原文地址:https://www.cnblogs.com/ccryolitecc/p/14069000.html