Codeforces Global Round 2

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章