题目:HDU4908BestCoder Sequence(组合数学)
题目大意:给出一串数字,要求找其中的子串,这个子串重新排序后,中位数是M,ps:M在这个串中只会出现一次。
解题思路:这题之前题意都没有理解清楚,还以为只能从M这个数的位置向左向右扩展的子串中找,但是因为是可以在重新排序的。所以这样的做法就不对了。
对于一个串来说,只要这个串是奇数长度,并且中位数在里面,而且这里面大于和小于中位数的长度相等,那么这个子串就是所求的。例如 ; 1 3 5中位数3.
那么每个数字都有个下标p,并且用两个数组A,B。A记录的是中位数位置之前(包括中位数的位置)的位置出现比M小的个数,B记录的是中位数位置之后的位置出现比M小的个数。
例如:1 2 3 4 5 M = 3
0 1 2 --- A (记录的个数不包括当前位置)
2 2 2 --- B (包括当前位置)那么Pi - Pj = 2 * (B【i】 - A【j】) 化简:Pi - 2 * B【i】 = Pj - 2 * A【j】 = K;所以只要找B中等于K的位置,和A中等于K的个数,相乘就是所求的。
代码:
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
const int N = 4e4 + 5;
typedef long long ll;
map<int , int> A, B;
map<int , int>::iterator it;
int main () {
int n, m;
int num;
while (scanf ("%d%d", &n, &m) != EOF) {
A.clear();
B.clear();
int i;
int sum = 0;
bool flag = 0;
for (i = 0; i < n; i++) {
scanf ("%d", &num);
if (num == m) {
flag = 1;
}
A[i - 2 * sum]++;
if (num < m)
sum++;
if (flag)
break;
}
B[i - 2 * sum]++;
for (int j = i + 1; j < n; j++) {
scanf ("%d", &num);
if (num < m)
sum++;
B[j - 2 * sum]++;
}
if (!flag)
printf ("0\n");
else {
int ans = 0;
for (it = A.begin(); it != A.end(); it++)
ans += A[it->first] * B[it->first];
printf ("%d\n", ans);
}
}
return 0;
}