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
    评论
ACM-ICPC(国际大学生程序设计竞赛)是一项面向大学生的计算机编程竞赛,涉及算法和数据结构等领域。在比赛中,选手需要解决一系列编程问题,使用合适的算法和数据结构来实现正确和高效的解决方案。 对于整理ACM-ICPC模板,以下是一些建议: 1. 了解比赛要求:首先,你需要了解ACM-ICPC比赛的具体要求和规则。这包括了解比赛所涉及的算法和数据结构,以及题目的类型和难度等。 2. 收集资料:收集与ACM-ICPC相关的资料,包括经典算法和数据结构的实现代码、常见问题的解题思路等。可以参考教材、博客、论文等资源。 3. 整理模板:将收集到的资料整理成模板。可以按照算法和数据结构的分类进行整理,例如排序算法、图算法、字符串算法等。对每个模板,添加必要的注释和示例代码,以便理解和使用。 4. 测试代码:对每个模板编写测试代码,确保它们的正确性和可靠性。可以使用已知的测试用例或自行设计测试用例。 5. 更新与扩充:定期更新和扩充模板,以适应ACM-ICPC比赛中新出现的算法和数据结构。同时,根据自己的经验和理解,对模板进行优化和改进。 6. 练习和复习:在比赛之前,利用整理好的模板进行练习和复习。尝试解决一些经典问题,使用模板中的算法和数据结构进行实现,并进行优化。 希望这些建议对你整理ACM-ICPC模板有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值