【洛谷P1627】 【CQOI2009】中位數

問題描述

有一個長度爲N的數列{A1,A2,...,AN},這N個數字剛好是1...N的一個排列。你須要求出這個序列有多少個子序列{Ai,Ai+1,...,Aj}知足:數組

一、i≤j且j-i+1爲奇數。spa

二、這個序列的中位數爲B。code

例如{5,1,3}的中位數爲3。blog

輸入格式

輸入文件第一行包含兩個正整數N和B,知足1≤N≤100000且1≤B≤N。io

第二行包含N個整數Aiclass

輸出格式

輸出文件僅包含一個整數,爲知足條件的子序列個數。原理

樣例輸入

7 4 di

5 7 2 4 3 1 6文件

樣例輸出

4co

題解

若是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 }
相關文章
相關標籤/搜索