#dp# 2018-2019 ACM-ICPC, NEERC, Southern Subregional Contest, Qualification Stage
阿新 • • 發佈:2018-11-11
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;
}