zoukankan      html  css  js  c++  java
  • 【洛谷P1627】 【CQOI2009】中位数

    问题描述

    有一个长度为N的数列{A1,A2,...,AN},这N个数字恰好是1...N的一个排列。你需要求出这个序列有多少个子序列{Ai,Ai+1,...,Aj}满足:

    1、i≤j且j-i+1为奇数。

    2、这个序列的中位数为B。

    例如{5,1,3}的中位数为3。

    输入格式

    输入文件第一行包含两个正整数N和B,满足1≤N≤100000且1≤B≤N。

    第二行包含N个整数Ai

    输出格式

    输出文件仅包含一个整数,为满足条件的子序列个数。

    样例输入

    7 4

    5 7 2 4 3 1 6

    样例输出

    4

    题解

    如果B是一个序列的中位数,那么这个序列中比B大的数的个数和比B小数的个数相等。事实上,我们不需要知道这些数的具体数值,只要知道这些数和B的大小关系就够了。

    把比B大的数记为1,比B小的数记为-1,分别计算以B为右端点的后缀和lsum和以B为左端点的前缀和rsum,对于任意一个子序列的左端点l和右端点r,当lsum[l]+rsum[r]==0时满足条件。

    设lnum[i]表示lsum[j]==i的lsum的个数,rnum[i]表示rsum[j]==i的rsum的个数,根据乘法原理,满足条件的子序列的个数为lnum[i]*rnum[-i]

    注意到lnum和rnum的下标可能为负,数组整体右移。

     1 #include <cstdio>
     2 int n,B,a[100005],lsum[100005],rsum[100005],lnum[200005],rnum[200005],ans;
     3 int main()
     4 {
     5     int i,j,p,l,r;
     6     scanf("%d%d",&n,&B);
     7     for (i=1;i<=n;i++)
     8       scanf("%d",&a[i]);
     9     for (p=1;p<=n && a[p]!=B;p++);
    10     lnum[n]=rnum[n]=1;
    11     for (i=p-1;i>=1;i--) 
    12       lsum[i]=a[i]>B?1:-1,
    13       lsum[i]+=lsum[i+1],
    14       lnum[lsum[i]+n]++;
    15     for (i=p+1;i<=n;i++) 
    16       rsum[i]=a[i]>B?1:-1,
    17       rsum[i]+=rsum[i-1],
    18       rnum[rsum[i]+n]++;
    19     for (i=-n;i<=n;i++)
    20        ans+=lnum[i+n]*rnum[-i+n];
    21     printf("%d",ans);
    22     return 0;
    23 }
  • 相关阅读:
    POJ 2486
    奇怪的电梯
    穿越泥地(mud)
    救援行动(save)
    As Fast As Possible
    Connecting Universities
    They Are Everywhere
    Cells Not Under Attack
    吃饭
    花店橱窗(flower)
  • 原文地址:https://www.cnblogs.com/rabbit1103/p/9852330.html
Copyright © 2011-2022 走看看