题目
题目描述:
给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后,位于中间的数。
输入描述:
第一行为两个正整数n和b ,第二行为1~n 的排列。
对于 30% 的数据中,满足 n≤100;
对于 60% 的数据中,满足 n≤1000;
对于 1100% 的数据中,满足n≤100000,1≤b≤n。
输出描述:
输出一个整数,即中位数为b的连续子序列个数。
思路:
1.子串中大于等于中位数的个数比小于中位数的个数多1。
2.通常的做法是把大于K的数赋值为1,小于K的数赋值为-1。
3.如果把等于K的数赋值为0,做法就是找到题目要求的K的位置,然后记录左边的后缀和,接着累加右边的前缀和的相反数在左边出现的次数,即前缀和+后缀和=0的个数,意思就是大于K的个数和小于K的个数相等,即K为中位数。
如果在算前缀和和后缀和的时候出现0值,也就是说0某一边大于K的个数和小于K的个数相等,即K为中位数。
4.如果把等于K的数赋值为1,判断区间[L+1,R]里的中位数是K的条件是(假设数组t记录的是每个数的新值,a记录的是前缀和)即:a[R]-a[L]=1。
所以在没找到K时,记录K左边的前缀和,当K出现且右端点是a[R]时,符合K为中位数的区间个数就是就是符合条件的左端点个数,而符合条件的左端点就是a[L]=a[R]-1,符合条件的左端点个数就是a[L]的个数。
Code:
#include<bits/stdc++.h> #define js ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) using namespace std; typedef long long ll; const int maxn = 100010; int qian[maxn<<1],sum,a[maxn],n,k,pos; int main() { js; cin>>n>>k; qian[n]=1; ll ans=0; for(ll i=1;i<=n;++i) { cin>>a[i]; if(a[i]==k) pos=i; if(a[i]>=k) ++sum; else --sum; if(!pos) ++qian[sum+n]; else ans+=qian[sum+n-1]; } cout<<ans<<endl; return 0; }