http://www.lydsy.com/JudgeOnline/problem.php?id=1303
依旧是题解流,,,不看题解没法活,,,第一眼就是瞎搞,然后就是暴力,显然TLE。。题解啊题解。。
这个特殊的技巧我不知道怎么抽象出来,,恩,,就说做法吧。。
首先读入的时候,小于b的赋值为-1,大于b的赋值为+1,并且用下标pos来索引b在数组的位置(1~n的排列哈~没看题的注意了)
然后用前缀和思想统计pos左边的前缀和和pos右边的前缀和,那么我们在统计的时候,只需要找(左边的一个前缀和+右边一个前缀和)==0的情况就行了,还不能理解吗?
怎么统计呢?我们再维护2个数组,l和r,l[i]表示左边所有sum[x]==i的数量,r[i]表示右边所有sum[x]==i的数量,根据乘法原理,将l[i]和r[0-i]乘起来就行了,累计乘积就是答案。
但是这里cpp是没有下标<0的情况的,所以我们要全部加到正的,(因为sum值可能=n,所以数组开到2n,来表示-n~n这个区间)
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
#define for1(i,a,n) for(i=a;i<=n;++i)
#define for2(i,a,n) for(i=a;i<n;++i)
#define for3(i,a,n) for(i=a;i>=n;--i)
#define for4(i,a,n) for(i=a;i>n;--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define read(a) scanf("%d", &a)
#define print(a) printf("%d", a) const int N=100005;
int w[N], l[N<<1], r[N<<1], sum[N], pos; int main() {
int i, n, b, ans=0;
read(n); read(b);
for1(i, 1, n) {
read(w[i]);
if(w[i]==b) pos=i, w[i]=0;
else w[i]=w[i]<b?-1:1;
}
l[n]=r[n]=1;
for3(i, pos-1, 1) sum[i]=sum[i+1]+w[i], l[n+sum[i]]++;
for1(i, pos+1, n) sum[i]=sum[i-1]+w[i], r[n+sum[i]]++;
for1(i, 0, n<<1) ans+=l[i]*r[(n<<1)-i];
print(ans);
return 0;
}
Description
给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后,位于中间的数。
Input
第一行为两个正整数n和b ,第二行为1~n 的排列。
Output
输出一个整数,即中位数为b的连续子序列个数。
Sample Input
7 4
5 7 2 4 3 1 6
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