zoukankan      html  css  js  c++  java
  • CF993E

    题意: 

      给你一个数组 $a_{1 sim n}$,对于 $k = 0 sim n$,求出有多少个数组上的区间满足:区间内恰好有 $k$ 个数比 $x$ 小。$x$ 为一个给定的数。
      $n le 2 imes 10^5$。值域没有意义。

    分析:

      对于$a_{i}$,若$a_{i}<x$则$a_{i}=1$,反之$a_{i}=0$。

      设$s$为$a$的前缀和,$c$数组为统计的数组,即求:  

    $$
    egin{align}
    &sum_{i=k}^{n}s_{i}s_{i-k}\
    &=sum_{i=k}^{n}s_{i}g_{n-i+k}\
    &=sum_{i+j=n+k}s_{i}g_{j}
    end{align}
    $$

      设$g_{j}=c_{n-i}$,再求卷积即可

      关于反转技巧,可以看这

      关于$ans_{0}$,从实际意义上考虑,是$0$串的个数,即所有$s_{i}=s_{j}$(之类的)的情况

      不想再打式子了,此时会有$i=j$的情况,共$n+1$组,其余由于相等会不分顺序算$2$次,所以要先减再除以$2$。

      本题答案很大,不可以$ntt$,只可用$fft$

    code:

      

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=1<<22;
    const double pi=acos(-1);
    struct comp{
        double x,y;
        comp(double xx=0,double yy=0){
            x=xx,y=yy;
        }
    };
    comp operator +(comp a,comp b){
        return comp(a.x+b.x,a.y+b.y);
    }
    comp operator -(comp a,comp b){
        return comp(a.x-b.x,a.y-b.y);
    }
    comp operator *(comp a,comp b){
        return comp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
    }
    int r[N],lim,L,n,m,a[N];
    comp c[N],d[N];
    void fft(comp *f,int fg){
        for(int i=0;i<lim;i++){
            if(i<r[i]){
                swap(f[i],f[r[i]]);
            }
        }
        for(int p=2;p<=lim;p<<=1){
            int len=p>>1;
            comp buf(cos(pi/len),fg*sin(pi/len));
            for(int j=0;j<lim;j+=p){
                comp t(1,0);
                for(int k=j;k<j+len;k++){
                    comp w=t*f[k+len];
                    f[k+len]=f[k]-w;
                    f[k]=f[k]+w;
                    t=t*buf;
                }
            }
        }
    }
    int main(){
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            int x;
            scanf("%d",&x);
            if(x<m) a[i]=1;
            a[i]+=a[i-1];
        }
        for(int i=0;i<=n;i++){
            c[a[i]].x++;
            d[n-a[i]]=c[a[i]];
        }
        while(1<<L<=2*n)L+=1;
        lim=1<<L;
        for(int i=0;i<lim;i++){
            r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
        }
        fft(c,1);
        fft(d,1);
        for(int i=0;i<lim;i++){
            c[i]=c[i]*d[i];
        }
        fft(c,-1);
        for(int i=0;i<=n;i++){
            if(i==0){
                printf("%.0lf ",(c[i+n].x/lim-n-1)/2+0.3);
            }
            else printf("%.0lf ",(c[i+n].x)/lim+0.3);
        }
        puts("");
        return 0;
    }

      

  • 相关阅读:
    一步一步教你elasticsearch在windows下的安装
    Query DSL for elasticsearch Query
    [转] webpack之前端性能优化(史上最全,不断更新中。。。)
    [转] Javascript模块化编程(一):模块的写法
    [转] 2016 JavaScript 发展现状大调查
    [转] 前端性能的几个基础指标
    [转] 视频直播前端方案
    [转] Web前端开发工程师常用技术网站整理
    [转] getBoundingClientRect判断元素是否可见
    [转] js前端解决跨域问题的8种方案(最新最全)
  • 原文地址:https://www.cnblogs.com/Hikigaya/p/11247522.html
Copyright © 2011-2022 走看看