CF993E Nikita and Order Statistics

小于x的赋值为1,否则为0

区间等于k的个数

求0~n连续的n+1个k?

N<=1e5?

FFT!

考虑卷积建模:用下标相加实现转移到位,数值相乘类比乘法原理!

法一:

分治,然后FFT没了

法二:

不分治也可以!区间查询->前缀相减

ans[j-i]=f[j]*f[i],f[i]表示数值为i的前缀和个数

减法怎么办?
reverse变成加法!

i->n-i

ans[j-i]=f[j]*f[i]=f[j]*f'[n-i]

FFT一下,n+j-i位置的值就是ans辣

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const double Pi=acos(-1);
const int N=2e5+5;
struct po{
    double x,y;
    po(){}
    po(double xx,double yy){
        x=xx;y=yy;
    }
    po friend operator +(po a,po b){
        return po(a.x+b.x,a.y+b.y);
    }
    po friend operator -(po a,po b){
        return po(a.x-b.x,a.y-b.y);
    }
    po friend operator *(po a,po b){
        return po(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
    }
}a[4*N],b[4*N];
int c[N],s[N];
int n,x;
int rev[4*N];
ll ans[N];
void fft(po *f,int c){
    for(reg i=0;i<n;++i){
        if(i<rev[i]) swap(f[i],f[rev[i]]);
    }
    for(reg p=2;p<=n;p<<=1){
        po gen;int len=p/2;
        gen=po(cos(Pi/len),c*sin(Pi/len));
        for(reg l=0;l<n;l+=p){
            po buf=po(1.0,0.0);
            for(reg k=l;k<l+len;++k){
                po tmp=f[k+len]*buf;
                f[k+len]=f[k]-tmp;
                f[k]=f[k]+tmp;
                buf=buf*gen;
            }
        }
    }
}
int main(){
    rd(n);rd(x);
    int lp=n;
    for(reg i=1;i<=n;++i) {
        rd(c[i]);c[i]=c[i]<x;
        s[i]=s[i-1]+c[i];
        ++a[s[i]].x;
    }
    ++a[s[0]].x;
    for(reg i=0;i<=n;++i){
        b[i].x=a[n-i].x;
    }
    int m;
    for(m=2*n,n=1;n<=m;n<<=1);
    for(reg i=0;i<n;++i){
        rev[i]=(rev[i>>1]>>1)|((i&1)?(n>>1):0);
    }
//    for(reg i=1;i<=lp;++i){
//        cout<<c[i]<<" ";
//    }cout<<endl;
//    for(reg i=0;i<n;++i){
//        cout<<a[i].x<<" ";
//    }cout<<endl;
//    for(reg j=0;j<n;++j){
//        cout<<b[j].x<<" ";
//    }cout<<endl;
    fft(a,1);
    fft(b,1);
    for(reg i=0;i<n;++i) b[i]=a[i]*b[i];
    fft(b,-1);
    for(reg i=0;i<=lp;++i) ans[i]=round(b[lp-i].x/n);
    //cout<<" ans[0] "<<ans[0]<<endl;
    ans[0]=(ans[0]+(lp+1))/2-(lp+1);
    for(reg i=0;i<=lp;++i){
        printf("%lld ",ans[i]);
    }
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2018/12/27 9:01:58
*/

 

reverse想法比较有意思!

值得注意!

 

posted @ 2018-12-27 19:36  *Miracle*  阅读(300)  评论(0编辑  收藏  举报