题目描述
给出 1~n 的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是 b。中位数是指
把所有元素从小到大排列后,位于中间的数。
分析
- 题面依旧简短的吓人。高考日的题果然玄妙到飞起来。
- (考完一查发现是2009重庆省选题???)
- 第一眼看题以为水的不行,于是非常快速的想了一种区间dp的办法。
- 然而….
- 打完之后发现题目说的是一种1到n的一种排列!!
- 排列!!!!!!
- 所以根本没有重复!!!!!!!
- 【看一眼自己以为很高端的技巧
- 然后再花了半小时改了一下。
- 超时三个点…
70分程序
#include
#include
#include
using namespace std;
void finit(){
#ifndef LOCAL
freopen("median.in","r",stdin);
freopen("median.out","w",stdout);
#endif
}
const int LIMIT=100001;
int dis[LIMIT],f[LIMIT];
int src[LIMIT],b,n;
int pt=0;
int val(int x){
return src[x]>b?1:src[x]1:0;
}
int main(){
finit();
scanf("%d%d",&n,&b);
for (int i=1;i<=n;i++){
scanf("%d",src+i);
dis[i]=val(i);
f[i]=(src[i]==b);
pt=(src[i]==b?i:pt);
}
for (int j=3;j<=n;j+=2){
int lim=min(pt+j-1,n-j+1);
for (int i=1;i<=n-j+1;i++)
dis[i]+=val(i+j-2)+val(i+j-1);
for (int i=max(1,pt-j+1);i<=lim;i++){
f[i]+=f[i+1]+f[i+2]+(dis[i]==0);
f[i+1]=f[i+2]=0;
}
}
printf("%d",f[2]+f[1]);
return 0;
}
- *&%!#@!!!!!!
- 心情复杂的看完评测结果。
- 于是问了问rym巨佬。
- 发现可以用前缀和存储上文程序的dis,可以避免每次都要更新整个dis数组。
- 当然rym的做法是从被查找数先向右边扫描,得出标记完的每个数的数字k。
- 再向左扫描与右边匹配,左侧与右侧为相反数则找到了一组解。
- 做这一步时可以对两侧的数组排序,也对奇数和偶数分开排序,可以免去个数的判断,也可以将查找复杂度降为log n。
先贴上dalao的程序,之后补自己写的。
rym巨佬的AC程序
#include
#include
#include
#include
#include
#include
using namespace std;
void fff(){
freopen("median.in","r",stdin);
freopen("median.out","w",stdout);
}
const int MAXN=100000;
int n,b;
int l1,l2,s1,s2;
int a[MAXN];
int ss[MAXN],t;
int r[MAXN*2+10];
int main(){
fff();
t=0;
scanf("%d%d",&n,&b);
for (int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(a[i]==b) t=i;
}
int k=MAXN;
r[k]=1;
for (int i=t+1;i<=n;i++){
if(a[i]else k--;
r[k]++;
}
k=MAXN;
int ans=r[MAXN];
for (int i=t-1;i>=1;i--){
if(a[i]else k--;
ans+=r[MAXN+MAXN-k];
}
printf("%d",ans);
return 0;
}