HDU4908BestCoder Sequence(组合数学)

题目: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;
}

                    

你可能感兴趣的:(HDU4908BestCoder Sequence(组合数学))