Codeforces Round #584 Div1 + Div2

A、B水题,C、D应该算是思维题,A题做的有点慢,不然应该有时间推一下C题

  • A. Paint the Numbers

题意:给一串序列,给序列中数染色,公因数相同的可以染同一颜色,求最少需要染的颜色
思路:首先排序,对一个数和所有序列中存在的其倍数染同一颜色,求出最终颜色数即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
const int inf = 0x3f3f3f3f;
int n, a[maxn], b[maxn];
int main()
{
	cin >> n;
	set<int> s;
	int ans = 0, maxx = 0;
	for (int i = 0; i < n; i++) {
		cin >> a[i];
		b[i] = 0;
		maxx = max(a[i], maxx);
		s.insert(a[i]);
	}
	sort(a, a+n);
	for (int i = 0; i < n; i++) {
		if (!b[a[i]])
			ans++;
		for (int j = a[i]; j <= maxx; j+=a[i]) {
			if (s.count(j)) {
				b[j] = ans;
			}
		}
	}
	cout << ans << "\n";
	return 0;
}
  • B. Koala and Lights

题意:给一串灯,1表示亮,0表示灭,每盏灯会重复点亮、熄灭,给出每盏灯开始重复的时间和重复周期,求出某个时间里点亮的最多灯数
思路:数据比较小(100),可以模拟个10000时间周期,求出最大点亮灯数即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
const int inf = 0x3f3f3f3f;
int n, a[maxn], b[maxn], sta[maxn], temp[maxn];
int main()
{
	cin >> n;
	int ans = 0, t = 0;
	string s;
	cin >> s;
	for (int i = 0; i < n; i++) {
		if (s[i] == '1') {
			sta[i] = 1;
			ans++;
		}
		else
			sta[i] = 0;
	}
	for (int i = 0; i < n; i++)
		cin >> a[i] >> b[i];
	memcpy(temp, sta, sizeof(sta));
	for (int j = 1; j < 10000; j++) {
		int cnt = 0;
		for (int i = 0; i < n; i++) {
			if (b[i] == j || (j-b[i] > 0 && (j-b[i]) % a[i] == 0))
				temp[i] = !temp[i];
			if (temp[i])
				cnt++;
		}
		ans = max(ans, cnt);
	}
	cout << ans << "\n";
	return 0;
}
  • C. Paint the Digits

题意:给一串序列,可以给数字染色1或者2,要求染色过后连续的1要在连续的2之前,且这样排列的串为递增序列
思路:首先将原序列排序放到另一数组里,和原序列对比,遍历两次,第一次染1,第二次染2,若这样过后还有元素没染色,则不存在答案,否则当前染色方案即为答案

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+10;
const int inf = 0x3f3f3f3f;
int n, T, c[maxn], b[maxn];
struct node {
	int index, val;
	node(int index = 0, int val = 0) : index(index), val(val) {
	}
}a[maxn];
bool cmp(node x, node y)
{
	return x.val < y.val;
}
int main()
{
	cin >> T;
	string s;
	for (int t = 0; t < T; t++) {
		cin >> n >> s;
		for (int i = 0; i < n; i++) {
			a[i] = node(i, s[i]-'0');
			b[i] = s[i]-'0';
		}
		sort(a, a+n, cmp);
		memset(c, 0, sizeof(c));
		int cur = 0;
		for (int i = 0; i < n; i++) {
			if (a[cur].val == b[i]) {
				c[i] = 1;
				cur++;
			}
		}
		for (int i = 0; i < n; i++) {
			if (a[cur].val == b[i] && !c[i]) {
				c[i] = 2;
				cur++;
			}
		}
		if (cur != n) {
			cout << "-\n";
			continue;
		}
		else {
			for (int i = 0; i < n; i++)
				cout <<  c[i];
			cout << "\n"; 
		}
	}
	return 0;
}
  • D. Cow and Snacks

题意:给k个奶牛,n个零食,每个奶牛有2个偏好零食,轮到某个奶牛时,它会将所有偏好零食吃完。要求对奶牛安排某一队列,使得没有零食可选的奶牛数最少,求出这样的奶牛个数
思路:可以将零食作为节点,奶牛作为边,显然两个点之间最多存在一条边,否则就会有奶牛没零食可选。用并查集将每个奶牛偏爱零食放到一个集合里,若某个奶牛两个偏爱零食已在同一集合,则其无零食可选

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int n, k, u[maxn];
int ufind(int x)
{
	if (u[x] != x)
		u[x] = ufind(u[x]);
	return u[x];
}
void unite(int x, int y)
{
	u[ufind(x)] = ufind(y);
}
int main()
{
//	freopen("test.txt", "r", stdin);
	cin >> n >> k;
	for (int i = 1; i <= n; i++)
		u[i] = i;
	int ans = 0;
	for (int i = 0; i < k; i++) {
		int x, y;
		cin >> x >> y;
		if (ufind(x) != ufind(y))
			unite(x, y);
		else
			ans++;
	}
	cout << ans << "\n";
	return 0;
}
  • G1. Into Blocks (easy version)

题意:给一个序列n个数字,可以把某个数字和序列中所有等于它的位置的数字变为另一数字,为了使所有相等的数字都相邻,求出需要更改的数字总个数
思路:一直以为后面的题都是复杂的算法题,结果这道是道简单题,认真推一下就可以得出答案,赛后直接一发AC了。实际上这道题就是求区间的并集,相同数字的最远距离构成一个区间,比如3 3 1 3 2 1 2的并集就是整个序列,若某两个区间存在交集,就需要更改数字,修改个数等于区间内不同数字中数量较少数字个数,从前往后存储区间位置,就可以保证答案是正确的

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+10;
const int inf = 0x3f3f3f3f;
int n, q, id[maxn], cnt = 0;
vector<vector<int> > m(maxn);
int main()
{
	cin >> n >> q;
	memset(id, 0, sizeof(id));
	for (int i = 1; i <= n; i++) {
		int k;
		cin >> k;
		if (!id[k])
			id[k] = ++cnt;
		m[id[k]].push_back(i);
	}
	int maxlen = 0, r = 1, ans = 0;
	for (int i = 1; i <= cnt; i++) {
		int len = m[i].size();
		if (m[i][0] < r) {
			if (maxlen > len) {
				ans += len;
			} else {
				ans += maxlen;
				maxlen = len;
			}
		} else {
			maxlen = 0;
		}
		if (m[i][len-1] > r) {
			r = m[i][len-1];
			maxlen = max(maxlen, len);
		}
	}
	cout << ans << "\n";
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值