CodeForces - 993E Nikita and Order Statistics

(暂时没有vjudge题面,CF的题面又太丑2333,直接口述了)

题目大意:给你一个长度为n的序列a[],和一个数x,对于每个i= 0~n ,求有多少个子区间满足恰好有i个数<x。

sol: 这不是FFT的套路题吗2333,直接做<的0/1前缀和,然后

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<vector>
#include<complex>
#define ll long long
using namespace std;
#define D double
#define E complex<double>
const int maxn=530005;
const D pi=acos(-1);

int n,N,l,r[maxn],X,cnt[maxn],A[maxn];
E a[maxn],b[maxn];
ll ans[maxn];

inline int read(){
	int x=0,f=1; char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
	return x*f;
}

void W(ll x){ if(x>=10) W(x/10); putchar(x%10+'0');}

inline void FFT(E *c,int F){
	for(int i=0;i<N;i++) if(i<r[i]) swap(c[i],c[r[i]]);
	
	for(int i=1;i<N;i<<=1){
		E omega(cos(pi/i),F*sin(pi/i));
		for(int P=i<<1,j=0;j<N;j+=P){
			E now(1,0);
			for(int k=0;k<i;k++,now*=omega){
				E x=c[j+k],y=c[j+k+i]*now;
				c[j+k]=x+y;
				c[j+k+i]=x-y;
			}
		}
	}
	
	if(F==-1) for(int i=0;i<N;i++) a[i]/=N;
}

inline void build(){
	for(int i=0;i<=n;i++) a[i]=b[n-i]=cnt[i];
	
	for(N=1;N<=(n<<1);N<<=1) l++;
	for(int i=0;i<N;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
}

inline void solve(){
	FFT(a,1),FFT(b,1);
	for(int i=0;i<N;i++) a[i]*=b[i];
	FFT(a,-1);
	
	ans[0]=(ll)(floor(a[n].real()+0.5)-n)>>1;
	for(int i=1;i<=n;i++) ans[i]=(ll)floor(a[n+i].real()+0.5);
}

int main(){
//	freopen("data.in","r",stdin);
//	freopen("data.out","w",stdout);
	
	n=read(),X=read(),cnt[0]++;
	for(int i=1;i<=n;i++){
		A[i]=A[i-1]+(read()<X);
		cnt[A[i]]++;
	}
	
	build();
	solve();
	
	for(int i=0;i<=n;i++) W(ans[i]),putchar(' ');
	return 0;
}

记录到cnt里直接卷一遍就好了2333.

猜你喜欢

转载自www.cnblogs.com/JYYHH/p/9192000.html