#dp# 2018-2019 ACM-ICPC, NEERC, Southern Subregional Contest, Qualification Stage

版权声明:本文为博主原创文章,转载清注明出处 https://blog.csdn.net/Jasmineaha/article/details/83099721

K. Medians and Partition

Description:

将一组数恰好分割成多组数,对每组数进行排序后,使得每组数的中位数大于等于m,求解最多可以分成多少组数

Solution:

ok[i][j]: 在 [i, j] 这段区间里的中位数是否符合要求,即 ok[i][j] = 1 代表 [i, j] 这段区间的中位数大于等于m
dp[i]:以 i 位置为结尾的区间划分最多可以划分成多少个区间段

先处理出任意一个子区间是否合法,即中位数是否大于等于m。
对于每个结尾的位置 i ,枚举位置每个小段区间的端点 j(也就是这些合法的 j 位置都可以将 [1, n] 这个完整区间分割成多个小段区间)
转移方程:dp[i] = max(dp[i], dp[j] + 1);

最后维护一下最大值作为答案即可。

其实对于求解任意一个子区间的中位数时,并不需要具体算出中位数是多少,只要能判断出与 m 的关系即可,比 m 大还是小。

代码:

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define fi first
#define se second
#define mst(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
const int Mod = 1e9 + 7;
const double pi = acos(-1);
const int MaxN = 5e3 + 5;

int a[MaxN];
int ok[MaxN][MaxN];
int dp[MaxN];

int main() 
{
	int n, m;
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
	for(int i = 1; i <= n; i++) {
		int cnt = 0; //记录当前[i,j]这个区间内有多少个数比m小,用来判断中位数与m的大小关系
		for(int j = i; j <= n; j++) {
			if(a[j] < m) cnt++;
			int mid = (j - i + 2) / 2; //中位数是第几个数,也就是“第几大数”
			if(cnt < mid) ok[i][j] = 1; //说明此时的中位数一定大于等于m
		}
	}
	for(int i = 1; i <= n; i++) {
		dp[i] = -INF;
		for(int j = 0; j < i; j++) {
			if(ok[j+1][i]) dp[i] = max(dp[i], dp[j] + 1);
		}
	}
	printf("%d\n", max(dp[n], 0));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Jasmineaha/article/details/83099721