E. Nikita and Order Statistics Codeforces Round #488 by NEAR (Div. 1) FFT

E. Nikita and Order Statistics
在这里插入图片描述

solution

求任意区间内小于 x x x 的元素个数,并按顺序输出 k = 0.. n k=0..n k=0..n 的区间数.

记录前缀和 a n s [ i ] ans[i] ans[i] 表示前 i i i 个数里小于 x x x 的元素个数.

区间 l , r l,r l,r 内小于 x x x 的元素个数为 a n s [ r ] − a n s [ l − 1 ] ans[r] - ans[l - 1] ans[r]ans[l1],即 x a n s [ r ] − a n s [ l − 1 ] x^{ans[r]-ans[l-1]} xans[r]ans[l1] 的系数.

由于 − a n s [ l − 1 ] -ans[l-1] ans[l1] 是负数,我们将其 + n +n +n 处理,就变成了 x a n s [ r ] + ( n − a n s [ l − 1 ] ) x^{ans[r]+(n - ans[l-1])} xans[r]+(nans[l1]).

得到 ∑ x i ∗ x n − i \sum x^i * x^{n - i} xixni,FFT之后得到的第 n + k n+k n+k 次项的系数,即小于 x x x 的元素个数为 k k k 的区间个数.

由于卷积的同时,会遇到 x k + ( n − k ) x^{k+(n-k)} xk+(nk) 的状况,即 k = 0 k=0 k=0 的项会多 ( n + 1 ) (n+1) (n+1) 次,我们将其减去,又因为 x i x^i xi x n − i x^{n-i} xni 重复了一遍,再除以2,得到 [ x 0 ] − n − 1 2 \frac{[x^0] - n - 1}{2} 2[x0]n1.

code

/*SiberianSquirrel*//*CuteKiloFish*/
#include <bits/stdc++.h>
using namespace std;
#define gcd(a,b) __gcd(a,b)
#define Polynomial vector<ll>
#define Inv(x) quick_pow(x, mod - 2)
#define DEBUG(x, y) cout << x << ": " << y << '\n';
#define rep(i, a, b) for(int i = a; i <= b; ++ i)
#define per(i, a, b) for(int i = a; i >= b; -- i)
#define mem(x, a) memset(x, a, sizeof x)
using ld = long double;
using ll = long long;
using ull = unsigned long long;
//const ll mod = 998244353, mod_g = 3, img = 86583718;
const ll mod = 1004535809, mod_g = 3;
const int N = int(1e5 + 10);
template<typename T> inline T read() {
    T x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
template<typename T> inline T print(T x) {
    if(x < 0) { putchar('-'); x =- x; }
    if(x > 9) print(x / 10);
    putchar(x % 10 + '0');
}

const ld pi = acos(-1.0);

struct Complex {
    ld r, i;
    Complex(ld _r = 0, ld _i = 0) : r(_r), i(_i) {}
    Complex operator + (const Complex &b) const {
        return Complex(r + b.r, i + b.i);
    }
    Complex operator - (const Complex &b) const {
        return Complex(r - b.r, i - b.i);
    }
    Complex operator * (const Complex &b) const {
        return Complex(r * b.r - i * b.i, r * b.i + i * b.r);
    }
    Complex operator / (const Complex &b) const {
        return Complex((r * b.r + i * b.i) / (b.r * b.r + b.i * b.i), (i * b.r - r * b.i) / (b.r * b.r + b.i * b.i));
    }
};


int R[int(1e6 + 10000)];
Complex x[int(1e6 + 10000)], y[int(1e6 + 10000)];

void get_R(int lim) {
    for (int i = 0; i < lim; i++) {
        R[i] = (i & 1) * (lim >> 1) + (R[i >> 1] >> 1);
    }
}

void FFT(Complex *f, int lim, int rev) {
    for (int i = 0; i < lim; i++) {
        if (i < R[i]) swap(f[i], f[R[i]]);
    }
    for (int mid = 1; mid < lim; mid <<= 1) {
        Complex wn = Complex(cos(pi / mid), rev * sin(pi / mid));
        for (int len = mid << 1, cur = 0; cur < lim; cur += len) {
            Complex w = Complex(1, 0);
            for (int k = 0; k < mid; k++, w = w * wn) {
                Complex x = f[cur + k], y = w * f[cur + mid + k];
                f[cur + k] = x + y, f[cur + mid + k] = x - y;
            }
        }
    }
    if (rev == -1) {
        for (int i = 0; i < lim; i++) {
            f[i].r /= lim;
        }
    }
}

ll quick_pow(ll ans, ll p, ll res = 1) {
    for(; p; p >>= 1, ans = ans * ans % mod)
        if(p & 1) res = res * ans % mod;
    return res % mod;
}

ll ans[200010];

inline void solve() {
    int n, X; cin >> n >> X;
    rep(i, 1, n) {
        int xx; cin >> xx;
        ans[i] = ans[i - 1] + (xx < X);
        x[ans[i]].r ++;
        y[200000 - ans[i]].r ++;
        x[i].i = y[i].i = 0;
    }
    x[0].r ++, y[200000].r ++;

    int lim = 1; while (lim <= 400000) lim <<= 1;
    get_R(lim);
    FFT(x, lim, 1);
    FFT(y, lim, 1);
    rep(i, 0, lim - 1) x[i] = x[i] * y[i];
    FFT(x, lim, -1);

    cout << (ll(x[200000].r + 0.5) - n - 1) / 2;
    rep(i, 1, n) cout << ' ' << ll(x[200000 + i].r + 0.5);
    cout << '\n';
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
//    freopen("output", "w", stdout);
    signed test_index_for_debug = 1;
    char acm_local_for_debug = 0;
    do {
        if (acm_local_for_debug == '$') exit(0);
        if (test_index_for_debug > 20)
            throw runtime_error("Check the stdin!!!");
        auto start_clock_for_debug = clock();
        solve();
        auto end_clock_for_debug = clock();
        cout << "Test " << test_index_for_debug << " successful" << endl;
        cerr << "Test " << test_index_for_debug++ << " Run Time: "
             << double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
        cout << "--------------------------------------------------" << endl;
    } while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
    solve();
#endif
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值