• CF993E Nikita and Order Statistics


    Solution

    考虑先将序列 (<a_i>) 转换,定义序列 (<b_i>)。令 (b_i=[a_i<X]),那么对 (b_i) 做前缀和的话,得到的 (s_i) 就表示前 (i) 个数中小于 (X) 的数的个数。那么对于一个特定的 (k) ,我们就需要回答 (s_i=s_j+k) 的有序对 ((i,j)) 的个数。我们成功地将区间计数转换成了元素统计,这实际上是这类问题的惯用伎俩。

    再进一步,(s) 相同的前缀可以合并,令 (c_i) 表示 (s=i) 的前缀个数。那么对于答案 (G(k)) ,就有

    [G(k)=sum_{i=0}^{m-k} c_i imes c_{i+k} ]

    其中 (m) 为所有小于 (X) 的数的个数,容易知道当 (i>m-k)(c_{i+k}) 都为零,所以不用统计。

    到了这一步就很简单了,容易发现是一个差卷积的形式。具体地,令 (A_{i}=c_i)(B_{i}=c_{m-i}),那么上式就可以写成

    [G(k)=sum_{i=0}^{m-k} A_{i} imes B_{m-i-k} ]

    求出 (A)(B) 的卷积后再把前 (m) 项 reverse 一下,就能得到 (G) 序列。复杂度 (O(nlog n))

    特别的,(G(0)) 并不能这么处理,我们可以单独算出 (G(0)),复杂度 (O(n))

    [G(0)=sum_{i=0}^m frac{c_i(c_i-1)}{2} ]

    #include<stdio.h>
    #include<math.h>
    #include<algorithm>
    using namespace std;
    #define N ((1<<21)+3)
    #define db double
    #define ll long long
    
    const db PI=acos(-1);
    
    inline int read(){
        int x=0,flag=1; char c=getchar();
        while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
        return flag? x:-x;
    }
    
    struct Complex{
        db x,y;
        Complex(db x_=0,db y_=0):x(x_),y(y_){}
        Complex operator +(const Complex X){return Complex(x+X.x,y+X.y);}
        Complex operator -(const Complex X){return Complex(x-X.x,y-X.y);}
        Complex operator *(const Complex X){return Complex(x*X.x-y*X.y,x*X.y+y*X.x);}
    }a[N];
    
    int n,X,m=0,op=0,rk[N];
    ll G[N];
    
    void FFT(){
        for(int i=0;i<n;i++)
            if(i<rk[i]) swap(a[i],a[rk[i]]);
        for(int p=2;p<=n;p<<=1){
            int len=p>>1;
            Complex w(cos(2*PI/p),op*sin(2*PI/p));
            for(int k=0;k<n;k+=p){
                Complex now(1.0,0.0);
                for(int l=k;l<k+len;l++){
                    Complex t=now*a[l+len];
                    a[l+len]=a[l]-t;
                    a[l]=a[l]+t;
                    now=now*w;
                }
            }
        }
    }
    
    int main(){
        n=read(),X=read();
        a[0]=1; int n_=n;ll ret=0;
        for(int i=1;i<=n;i++){
            int x=read();
            if(x<X) a[++m].x=1;
            else a[m].x++;
        }
        for(int i=0;i<=m;i++) a[m-i].y=a[i].x,ret+=(ll)a[i].x*(a[i].x-1)/2;
        for(n=1;n<=(m<<1);n<<=1);
        for(int i=0;i<n;i++)
            rk[i]=(rk[i>>1]>>1)|((i&1)? n>>1:0);
        op=1,FFT();
        for(int i=0;i<n;i++) a[i]=a[i]*a[i];
        op=-1,FFT();
        for(int i=0;i<=m;i++) G[i]=(ll)(a[i].y/n/2+0.5);
        reverse(G,G+1+m),G[0]=ret;
        for(int i=0;i<=n_;i++) printf("%lld ",G[i]);
    }
    
  • 相关阅读:
    ssh -vT git@github.com get “ No such file or directory” 错误
    提高Bash使用效率的方法
    mybatis的update使用选择
    Ping 的TTL理解
    为什么要使用oath协议?
    Rest Client插件简单介绍
    idea中查看java类继承图
    CSS单行文本溢出显示省略号
    js里父页面与子页面的相互调用
    css font的简写规则
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/14363493.html
Copyright © 2020-2023  润新知