CF993E Nikita and Order Statistics

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF993E Nikita and Order Statistics相关的知识,希望对你有一定的参考价值。

CF993E Nikita and Order Statistics

题意:

给你一个数组 a 1 ∼ n a_1 \\sim n a1n,对于 k = 0 ∼ n k = 0 \\sim n k=0n,求出有多少个数组上的区间满足:区间内恰好有 k 个数比 x 小。 x 为一个给定的数。
n ≤ 2 × 1 0 5 n \\le 2 \\times 10^5 n2×105
− 1 e 9 < = a i < = 1 e 9 -1e9<=a_i<=1e9 1e9<=ai<=1e9

题解:

因为x是常数,也就是说对于每个数只有贡献和无贡献之分
所以我们把所有大于等于X的数都改为0,小于X的数都改为1,这样原问题就转化为问有多少个连续序列满足和为k
用公式表示就是: ∑ i = 1 n ∑ j = 1 n [ a i − a j = k ] \\sum_i=1^n\\sum_j=1^n[a_i-a_j=k] i=1nj=1n[aiaj=k]
设前缀和 s u m i = ∑ j = 1 i a j sum_i=\\sum_j=1^ia_j sumi=j=1iaj
再设 S i = ∑ [ s u m j = i ] , S 0 = 0 S_i=\\sum[sum_j=i],S_0=0 Si=[sumj=i],S0=0, S i S_i Si就表示前缀和等于i的数量
原问题就变成求: ∑ i = k + 1 n S i ⋅ S i − k \\sum_i=k+1^nS_i⋅S_i-k i=k+1nSiSik
比如k=2时,我们要查询区间和等于2的数量,答案就是区间前缀和等于3的数量乘以区间和等于1的数量,前缀和等于4的数量乘以前缀和等于2的数量…。因为前缀和等于3的减去前缀和等于1得到的这段区间一定是等于2的,因此可以这样转化
这个式子看着愈发熟悉。。好像是卷积,卷起来
∑ i = k + 1 n S i ⋅ S i − k = ∑ i − j = k S i ⋅ S j = ∑ i + j = k S i ⋅ S − j = ∑ i + j = n + k S i ⋅ S n − j \\sum_i=k+1^nS_i⋅S_i-k=\\sum_i-j=kS_i⋅S_j=\\sum_i+j=kS_i⋅S_-j=\\sum_i+j=n+kS_i⋅S_n-j i=k+1nSiSik=ij=kSiSj=i+j=kSiSj=i+j=n+kSiSnj
答案就是n+k的系数,k=0时要特判

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const double PI=acos(-1.0);
struct Complex
    double x,y;
    Complex(double _x=0.0,double _y=0.0)
        x=_x;
        y=_y;
    
    Complex operator -(const Complex &b)const
        return Complex(x-b.x,y-b.y);
    
    Complex operator +(const Complex &b)const
        return Complex(x+b.x,y+b.y);
    
    Complex operator *(const Complex &b)const
        return Complex(x*b.x-y*b.y,x*b.y+y*b.x);
    
;
void change(Complex y[],int len)

    int i,j,k;
    for(i=1,j=len/2;i<len-1;i++)
    
        if(i<j) swap(y[i],y[j]);
        k=len/2;
        while(j>=k)
        
            j-=k;
            k/=2;
        
        if(j<k)j+=k;
    

void fft(Complex y[],int len,int on)

    change(y,len);
    for(int h=2;h<=len;h<<=1)
    
        Complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h));
        for(int j=0;j<len;j+=h)
        
            Complex w(1,0);
            for(int k=j;k<j+h/2;k++)
            
                Complex u=y[k];
                Complex t=w*y[k+h/2];
                y[k]=u+t;
                y[k+h/2]=u-t;
                w=w*wn;
            
        
    
    if(on==-1)
        for(int i=0;i<len;i++)
        y[i].x/=len;

const int MAXN=800010;
Complex x1[MAXN],x2[MAXN];
int str1[MAXN/2],str2[MAXN/2],a[MAXN];
ll sum[MAXN];
int _sum[MAXN];
int t,n,x;
int main()

    scanf("%d%d",&n,&x);
    memset(str1,0,sizeof str1);
    memset(str2,0,sizeof str2);
    str1[0]=1;
    for(int i=1;i<=n;i++)
    
        scanf("%d",&a[i]);
        if(a[i]<x)a[i]=1;
        else a[i]=0;
        _sum[i]=_sum[i-1]+a[i];
        str1[_sum[i]]+=1;
    
    for(int i=0;i<=n;i++)
    	str2[i]=str1[n-i];
	
    int len=1,len1=n+1,len2=n+1;
    while(len<len1*2||len<len2*2) len<<=1;
    for(int i=0;i<len1;i++)
        x1[i]=Complex(str1[i],0);
    for(int i=len1;i<len;i++)
        x1[i]=Complex(0,0);
    for(int i=0;i<len2;i++)
        x2[i]=Complex(str2[i],0);
    for(int i=len2;i<len;i++)
        x2[i]=Complex(0,0);
//    for(int i=0;i<len;i++)
//    	cout<<x2[i].x<<" "; 
//	 
//	cout<<endl;
//	cout<<"--"<<endl;
//	for(int i=0;i<len;i++)
//    	cout<<str2[i]<<" "; 
//	 cout<<endl;
    fft(x1,len,1);
    fft(x2,len,1);
    for(int i=0;i<len;i++)
        x1[i]=x1[i]*x2[i];
//    for(int i=0;i<len;i++)
//        cout<<"x1[i]="<<x1[i].x<<endl;
//    cout<<endl;
    fft(x1,len,-1);
    
    ll ans=0,num=0;
    for(int i=1;i<=n+1;i++)
    	if(a[i以上是关于CF993E Nikita and Order Statistics的主要内容,如果未能解决你的问题,请参考以下文章

CF993E Nikita and Order Statistics

CF993E Nikita and Order Statistics

CF993E Nikita and Order Statistics

CodeForces - 993E Nikita and Order Statistics

Nikita and Order Statistics

CF842E Nikita and game