题目: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; }
时间: 2024-09-09 05:12:28