中位数(median.pas/c/cpp)HGOI0608

中位数(median.pas/c/cpp)HGOI0608

题目描述

给出 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;
}

你可能感兴趣的:(oi)