想明白算法之后特别水,因为b只有可能出现一次,所以直接在b的左右找就行了,比他大的为1,比他小的为-1,然后维护前缀和就行了。
假如b有可能出现多次呢?按照这种方法好像也很好办,就是枚举每个点就行了,复杂度有点大,所以直接求一遍前缀和就行了。
题干:
Description 给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后,位于中间的数。 Input 第一行为两个正整数n和b ,第二行为1~n 的排列。 Output 输出一个整数,即中位数为b的连续子序列个数。 Sample Input 7 4 5 7 2 4 3 1 6 Sample Output 4 HINT 第三个样例解释:{4}, {7,2,4}, {5,7,2,4,3}和{5,7,2,4,3,1,6} N<=100000
代码:
#include<iostream> #include<cstdio> #include<cmath> #include<ctime> #include<queue> #include<algorithm> #include<cstring> using namespace std; #define duke(i,a,n) for(int i = a;i <= n;i++) #define lv(i,a,n) for(int i = a;i >= n;i--) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } int n,b,point; int a[100010],sum[200010]; int l[100010],r[100010]; int main() { read(n);read(b); duke(i,1,n) { read(a[i]); if(a[i] > b) a[i] = 1; else if(a[i] == b) { a[i] = 0; point = i; } else a[i] = -1; } l[n] = 1;r[n] = 1; lv(i,point - 1,1) { sum[i] = sum[i + 1] + a[i]; l[sum[i] + n]++; } duke(i,point + 1,n) { sum[i] = sum[i - 1] + a[i]; r[sum[i] + n] ++; } int ans = 0; duke(i,0,2 * n - 1) { ans += l[i] * r[2 * n - i]; } printf("%d ",ans); return 0; } /* 7 4 5 7 2 4 3 1 6 */