bzoj 1303
很容易想到把大于b的数赋值为1,小于b的数赋值为-1。
做一遍前缀和。
于是问题变成求sum[j]-sum[i]=0 (0<=i<w && j>=w)
于是直接按照b所在位置划分成两段,分别用桶统计sum某值出现的次数,注意sum数组中的数可能会出现负数,于是要加上一个n防止访问负的下标。
最后用乘法原理统计答案即可。
#include"cstdio" #include"cctype" int read() { int c,x=0; while(!isdigit(c=getchar())); while(x=x*10+c-'0',isdigit(c=getchar())); return x; } int a[100001],s[100001],h[200001],t[200001]; int main() { int n=read(),b=read(),w; long long ans=0; for(int i=1; i<=n; i++) { a[i]=read(); if(a[i]==b) w=i,a[i]=0; else if(a[i]>b) a[i]=1; else a[i]=-1; s[i]=s[i-1]+a[i]; } for(int i=0; i<w; i++) h[s[i]+n]++; for(int i=n; i>=w; i--) t[s[i]+n]++; for(int i=0; i<=n*2; i++) ans+=(long long)h[i]*t[i]; printf("%lld",ans); return 0; }
设b所在位置为w。
其实也可以按照w划分为两段,然后往前做一次后缀和,往后做一次前缀和。
记s1[i]表示从i往后一直到w的和。
记s2[i]表示从i往前一直到w的和。
于是求s1[i]+s2[j]=0 (1<=i<=w && w<=j<=n)
用两个桶分别统计一下s1和s2中某值出现的个数,还是要加上n防止访问负的下标。
最后还是乘法原理统计答案。
#include"cstdio" #include"cctype" int read() { int c,x=0; while(!isdigit(c=getchar())); while(x=x*10+c-'0',isdigit(c=getchar())); return x; } int a[100001],s1[100001],s2[100001],h[200001],t[200001]; int main() { int n=read(),b=read(),w; long long ans=0; for(int i=1; i<=n; i++) { a[i]=read(); if(a[i]==b) w=i,a[i]=0; else if(a[i]>b) a[i]=1; else a[i]=-1; } h[n]=t[n]=1; for(int i=w-1; i>=1; i--) s1[i]=s1[i+1]+a[i],h[s1[i]+n]++; for(int i=w+1; i<=n; i++) s2[i]=s2[i-1]+a[i],t[s2[i]+n]++; for(int i=0; i<=n*2; i++) ans+=(long long)h[i]*t[2*n-i]; printf("%lld",ans); return 0; }