【每日一题】5月22日中位数图
[CQOI2009]中位数图
https://ac.nowcoder.com/acm/problem/19913
题意
给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后,位于中间的数输入描述
第一行为两个正整数n和b ,第二行为1~n 的排列。输出描述
输出一个整数,即中位数为b的连续子序列个数。解析
首先我并不知道为啥名字要带个图,首先我们来看,这个序列中所有的数都是连续的,只不过排列顺序不对,**并且每一个数只有一个**,这就让这个题的难度降低了很多。我们看这个题,要求我们求出这个数字b所在的区间b正好是中位数的区间,这个中位数我们要考虑几个地方:
1.这个区间中的数字的个数要为奇数
2.在这个序列中大于b的数字的个数要等与小于b的数字的个数。
通过上面这两个条件我们就可以做出这个题,我们首先把不需要的元素去掉,首先我们并不需要知道比数字b大的数字是啥,比他小的又是啥,我们可以把比他大的数字用1代替,比它小的数字用-1代替,然后和他相等的数字用0表示,这样子如果这个区间存在b并且这个区间的和为0,这样在这个区间中b就是这个区间的中位数。这里我们用前缀和来做(用前缀和可以很快的知道这个区间的和),因为可能会出现负数,所以我们采用map,或者加上一定的基数,比如我们用sum[1000]代替sum[0]这样子如果出现了sum[-2]那么就等于sum[998]
代码
#include<bits/stdc++.h> typedef long long ll; using namespace std; const int MAXN=1e5+5; ll a[MAXN]; map<int,int>mp; int main(void){ ll n,b,ans,now; ans=0; cin>>n>>b; for(int i=1;i<=n;++i){ cin>>a[i]; if(a[i]>b) a[i]=-1; else if(a[i]==b){ a[i]=0; now=i; } else a[i]=1; } ll sum=0; for(int i=now;i<=n;++i){ sum+=a[i]; mp[sum]++; } sum=0; for(int i=now;i;--i){ sum+=a[i]; ans+=mp[-sum]; } cout<<ans<<endl; return 0; }
每日一题 文章被收录于专栏
写每日一题呀