时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言524288K 64bit IO Format: %lld
题目描述
给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后,位于中间的数。
输入描述:
第一行为两个正整数n和b ,第二行为1~n 的排列
输出描述:
输出一个整数,即中位数为b的连续子序列个数。
示例1
输入
7 4 5 7 2 4 3 1 6
输出
4
题解:
b是中位数,在b后面的比b大,前面的比b小,比b大多少小多少都无所谓,所以我们可以把大于b的数记为1,小于的记为-1,相等的记为0,这样的话,我们要找一个什么样的区间?一个奇数区间的和是0且0的长度还是奇数(和为0说明左右两边-1和1数量相等,且最中间为0是我们所要的b)
我们可以以0开始分别分析左右两边,统计0的左边后缀和为i的个数,右边的前缀和为i的个数,为了保证两边数量相同,就要使右边的前缀和与左边的前缀和互为相反数。(左右前缀和均从0开始)
样例:
5 7 2 4 3 1 6
化为-1,0,1
1 1 -1 0 -1 -1 1
0的左边前缀和(从0开始)
1 0 -1
右边
-1 -2 -1
左边一个-1可以和右边两个-1搭配,两个答案
左边一个0,不与右边搭配,一个答案
b本身,一个答案
总:四个答案
代码:
(代码仅提供思路)
#include<iostream> #include<cstdio> #include<algorithm> #define maxn 1e6+4 using namespace std; int a[maxn]; map<int,int >b; int main() { int n,m; cin>>n>>m; int pos,sum=0; for(int i=1;i<=n;i++) { cin>>a[i]; if(a[i]<m)a[i]=-1; else if(a[i]>m)a[i]=1; else { a[i]=0; pos=i; } } b[0]=1;//和为0则符合条件 int tot=0; for(int i=pos-1;i;i--) { if(a[i]==1)sum--;//前缀和 else sum++; if(sum==0)tot++;//存在0就直接加 b[tot]++; } for(int i=pos+1;i<=n;i++) { if(a[i]==1)sum--; else sum++: ans+=b[-sum];//查看相反数有多少个 } printf("%d",tot); return 0; }