/********************************************** ** Description: 给出1~n(<=50000)的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。 中位数是指把所有元素从小到大排列后,位于中间的数。 ** Sample Input:1//test cases 7 4 //n b 5 7 2 4 3 1 6 ** Sample Output:4//{4}, {7,2,4}, {5,7,2,4,3}和{5,7,2,4,3,1,6} ** Algorithm: 数学+二分枚举 ** Analysis: 1.a[i] = sgn(c[i]-b), s[i] = a[1]+a[2]+...+a[i] 2.则原问题等价于求 s[A]=s[B],其中0 <= A < C <= B <= N, c[C] = b 3.于是可以把0——C-1和C——N排序,然后二分去找左右中有多少相同的; 4.如果这一次和前一次找的数字相同,则不用重复做; ** NOTE: 对于二分的训练,这是一道很好的题目! **********************************************/ #include <iostream> #include <stdio.h> #include <algorithm> #define MAXN 100010 using namespace std; int cases, n, b, i, m, p; int s[MAXN]; int Binary1(int k) { int l = p-1, r = n+1; while (l+1 < r) { int mid = (l+r)/2; if (s[mid]<k) l = mid; else r = mid; } return l; } int Binary2(int k) { int l = p, r = n+1; while (l+1 < r) { int mid = (l+r)/2; if (s[mid]<=k) l = mid; else r = mid; } return r; } int main() { freopen("b.in", "r", stdin); scanf("%d", &cases); while (cases--) { scanf("%d%d", &n, &b); s[0] = 0; p = 0; for (i = 1; i <= n; i++) { scanf("%d", &m); if (m > b) m = 1; else if (m < b) m = -1; else m = 0, p = i; s[i] = s[i-1]+m; } sort(s,s+p); sort(s+p, s+n+1); int ans = 0, last = -1 << 20; for (i = 0; i < p; i++) { if (s[i] >= s[p] && s[i] <= s[n]) { if (i >= 1 && s[i] == s[i-1]) { ans += last; continue; } int k1 = Binary1(s[i]);//满足s[k2] < s[i], s[k1+1] >= s[i] int k2 = Binary2(s[i]);//满足S[k2] > s[i], s[k2-1] <= s[i] //cout << k1 << " " << k2 << endl; last = k2-k1-1; ans += last; } } printf("%d/n", ans); } return 0; }