Codeforces Global Round 2

22 篇文章 0 订阅
19 篇文章 0 订阅

题目链接

A. Ilya and a Colorful Walk

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 3e5 + 10;
int a[N];

int main()
{
#ifdef LOCAL
	//freopen("C:/input.txt", "r", stdin);
#endif
	int n, ans = 0;
	cin >> n;
	for (int i = 1; i <= n; ++i)
		scanf("%d", &a[i]);
	for (int i = 2; i <= n; ++i)
		if (a[i] != a[1])
			ans = i - 1;
	for (int i = n; i >= 2; --i)
		if (a[i] != a[n])
			ans = max(ans, n - i);
	cout << ans << endl;

	return 0;
}

B. Alyona and a Narrow Fridge <二分> <贪心>

二分答案求解,每次二分一个能填装的数量m。
贪心思路,按照顺序将前m个瓶子装入vector并排序,每次将高度最相近的两个装在同一层,则当前层所需高度为max(v[i], v[i + 1]),如果最终答案小于等于限制高度则可行尝试增大m。

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e3 + 10;
int a[N];
ll n, h;

bool check(int m)
{
	vector<int> v;
	for (int i = 1; i <= m; ++i)
		v.push_back(a[i]);
	sort(v.begin(), v.end(), greater<int>());
	ll hh = h;
	for (int i = 0; i < v.size(); i += 2)
		hh -= v[i];
	return hh >= 0;
}
int main()
{
#ifdef LOCAL
	//freopen("C:/input.txt", "r", stdin);
#endif
	cin >> n >> h;
	for (int i = 1; i <= n; ++i)
		scanf("%d", &a[i]);
	int l = 0, r = n, ans = 0;
	while (l <= r)
	{
		int m = l + r >> 1;
		if (check(m))
			l = m + 1, ans = m;
		else
			r = m - 1;
	}
	cout << ans << endl;

	return 0;
}

C. Ramesses and Corner Inversion <思维> <构造>

直接将A矩阵和B矩阵进行异或,得到矩阵C,矩阵C某个位置为1则表示之前AB矩阵不相同,即如果能将C矩阵全变为0则可以将AB变换为相同。
如果C矩阵同一行内1个数为奇数则一定无法将当前行的1全部清除,如果为偶数则定能。并且会给下面某行造成偶数个影响(1个数+2、-2、0),所以不会影响下一行。
所以只需要将当前行两个1和下一行相邻的位置进行反转即可,一行一行反转下去如果最后全为0则为YES否则NO。

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 510;
int g[N][N];

int main()
{
#ifdef LOCAL
	freopen("C:/input.txt", "r", stdin);
#endif
	int n, m, x;
	cin >> n >> m;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j)
			scanf("%d", &g[i][j]);
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j)
		{
			scanf("%d", &x);
			g[i][j] ^= x;
		}
	for (int i = 1; i < n; ++i)
	{
		for (int j = 1; j <= m; ++j)
			if (g[i][j])
				for (int k = j + 1; k <= m; ++k)
					if (g[i][k])
					{
						g[i][j] ^= 1;
						g[i][k] ^= 1;
						g[i + 1][j] ^= 1;
						g[i + 1][k] ^= 1;
						break;
					}
	}
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j)
			if (g[i][j])
				cout << "No" << endl, exit(0);
	cout << "Yes" << endl;

	return 0;
}

D. Frets On Fire <思维> <二分>

因为每行增长速度相同,所以对于每个查询区间[l, r]可以转换为[0, r-l+1]而不影响答案。
将行按照第一个位置进行排序,不影响答案。排序后对于每个行i最大能造成的贡献则为s[i+1]-s[i],因为超过s[i+1]则后面都会被下一行包含,所以每行的贡献则为min(s[i + 1] - s[i], r - l + 1),最后一行的贡献只受r - l + 1影响。
两两做差,按照差值排序,并且从前向后做前缀和。对于每个查询找到第一个大于r - l + 1的位置k,在k之前的则收到自身与前面距离影响,使用前缀和计算。后k到n个受r - l + 1限制,直接区间长度*个数求和即可。

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e5 + 10;
ll a[N], s[N];

int main()
{
#ifdef LOCAL
	freopen("C:/input.txt", "r", stdin);
#endif
	int n;
	cin >> n;
	for (int i = 1; i <= n; ++i)
		scanf("%I64d", &a[i]);
	sort(a + 1, a + n + 1);
	for (int i = 1; i < n; ++i)
		a[i] = a[i + 1] - a[i]; //当前位置的最大贡献
	a[n] = LINF; //最后位置为无穷大
	sort(a + 1, a + n + 1); //将贡献排序
	for (int i = 1; i <= n; ++i)
		s[i] = s[i - 1] + a[i]; //前缀和
	int q;
	cin >> q;
	while (q--)
	{
		ll l, r;
		scanf("%I64d%I64d", &l, &r);
		ll m = r - l + 1; //查询长度
		int k = upper_bound(a + 1, a + n + 1, m) - a; //k以前的都可以达到最大贡献
		ll res = s[k - 1] + (n - k + 1) * m; //k和以后的数量*m
		printf("%I64d\n", res);
	}

	return 0;
}

E. Pavel and Triangles <贪心>

由于木棒长度为2的次幂,所以只能3个相同的组成三角形或者2个大的1个小的组成三角形。
贪心策略,优先匹配剩余的小的木棒,然后尝试三个相同的一组,最后剩下的再加进剩余的里面。

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 3e5 + 10;
ll a[N];

int main()
{
#ifdef LOCAL
	//freopen("C:/input.txt", "r", stdin);
#endif
	int n;
	cin >> n;
	for (int i = 1; i <= n; ++i)
		scanf("%I64d", &a[i]);
	ll ans = 0, s = 0, k = 0; //k剩下的单个的
	for (int i = 1; i <= n; ++i)
	{
		int p = min(k, a[i] / 2); //优先匹配剩余
		ans += p;
		a[i] -= p * 2; //扣除对应数量
		k -= p;
		ans += a[i] / 3; //剩余的三个匹配
		k += a[i] % 3; //把最后加进剩余
	}
	cout << ans << endl;

	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值