2018-2019 ACM-ICPC, NEERC, Southern Subregional Contest, Qualification Stage K. Medians and Partitio

好久没写博客了呀,今天写一个。才不是因为今天发博客可以得一个勋章

题目链接:http://codeforces.com/gym/101911/problem/K

题目大意:给一个长度为n的数组和一个整数m,让你往中间插板子,问你最多有多少个子区间满足排完序后中位数大于等于m(序列长度为偶数的话去中间两个较小的一个)。

解题思路:最开始想着划分树什么的,看了看别人的题解,用dp可以求解。

===写作业去了,思路待会再写

update:

用一个数组vis[i][j]标记区间[i, j]是符合条件的区间,dp[i]表示以i为结尾的区间中,最多能分成的区间个数

那么dp[n]就是答案了

考虑dp细节:

其实很显然了。。对于每一个右端点,枚举每一个左端点,dp[i] = max(dp[i], dp[j] + 1);

这样时间复杂度O(n ^ 2)

#pragma GCC diagnostic error "-std=c++11" 
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<string>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<ext/rope>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define lowbit(x) x & (-x)
#define PII  pair<int, int> 
#define all(x) x.begin(), x.end()
#define FAST ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)1e4 + 5;
using namespace std;
using __gnu_cxx::crope;

int a[maxn], dp[maxn];
bool vis[maxn][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;
		for(int j = i; j <= n; j++){
			if(a[j] < m) cnt++;
			int mid = (j - i + 2) / 2;
			if(cnt < mid) vis[i][j] = 1;
		}
	}
	for(int i = 1; i <= n; i++){
		dp[i] = -inf;
		for(int j = 0; j < i; j++){
			if(vis[j+1][i]) dp[i] = max(dp[i], dp[j] + 1);
		}
	}
	printf("%d\n", max(dp[n], 0));
	return 0;
}

总觉得会有更快的解法,读了读别人代码,看到一个O(n)的解法:

其实对于出现的一个小于m的数,想让它所在的区间中位数大于m,需要再拉两个大于等于m的来和它组成一个区间,实际上,就算这样的数是连着的,也不会影响统计答案,因为一个小于m的数所带来的影响是一样的,那么只需要统计出来小于m的数cnt,答案就是n - 2 * cnt 了。

#pragma GCC diagnostic error "-std=c++11" 
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<string>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<ext/rope>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define lowbit(x) x & (-x)
#define PII  pair<int, int> 
#define all(x) x.begin(), x.end()
#define FAST ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)1e4 + 5;
using namespace std;
using __gnu_cxx::crope;

int main()
{
	int n, m, x, cnt = 0;
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i++){
		scanf("%d", &x);
		if(x < m) cnt++;
	}
	printf("%d\n", max(0, n - 2 * cnt));
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值