Codeforces Round #552 (Div. 3) 題解

題目鏈接

A. Restoring Three Numbers

#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;

int main()
{
#ifdef LOCAL
	//freopen("C:/input.txt", "r", stdin);
#endif
	ll x, y, z, p;
	cin >> x >> y >> z >> p;
	if (p < x)
		swap(x, p);
	if (p < y)
		swap(y, p);
	if (p < z)
		swap(z, p);
	printf("%I64d %I64d %I64d\n", p - x, p - y, p - z);

	return 0;
}

B. Make Them Equal

可以將某個數字加一次v或者減一次v不限制操作次數 找到一個最小的v可以將數字變爲相同

#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;

int main()
{
#ifdef LOCAL
	//freopen("C:/input.txt", "r", stdin);
#endif
	vector<int> v;
	int n;
	cin >> n;
	for (int i = 0; i < n; ++i)
	{
		int x;
		cin >> x;
		v.push_back(x);
	}
	sort(v.begin(), v.end());
	v.erase(unique(v.begin(), v.end()), v.end());
	if (v.size() > 3)
		cout << -1 << endl, exit(0);
	if (v.size() == 3 && v[1] - v[0] != v[2] - v[1])
		cout << -1 << endl, exit(0);
	if (v.size() == 3)
		cout << v[1] - v[0] << endl;
	else if (v.size() == 2)
	{
		int x = v[1] - v[0];
		if (x % 2 == 0)
			x /= 2;
		cout << x << endl;
	}
	else
		cout << 0 << endl;

	return 0;
}

C. Gourmet Cat <枚舉>

三種食物 告訴你周幾喫哪種食物 問從周幾齣發能夠喫的最長時間

#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;

int main()
{
#ifdef LOCAL
	//freopen("C:/input.txt", "r", stdin);
#endif
	ll x[3], z[3];
	cin >> x[0] >> x[1] >> x[2]; //147 26 35
	ll X = min({ x[0] / 3, x[1] / 2, x[2] / 2 }); //整週
	x[0] -= X * 3, x[1] -= X * 2, x[2] -= X * 2; //餘下物品
	ll ans = X * 7;
	int y[] = { 0, 1, 2, 0, 2, 1, 0 };
	for (int i = 0; i < 7; ++i) //開始
	{
		z[0] = x[0], z[1] = x[1], z[2] = x[2];
		int cnt = 0;
		for (int j = i; z[y[j]]--; j = (j + 1) % 7)
			cnt++;
		ans = max(ans, X * 7 + cnt);
	}
	cout << ans << endl;

	return 0;
}

D. Walking Robot <模擬>

機器人有普通電池和太陽能充電電池 0爲無光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;

int main()
{
#ifdef LOCAL
	//freopen("C:/input.txt", "r", stdin);
#endif
	int n, a, b; //充電電池 電池
	cin >> n >> b >> a;
	int A = a, B = b;
	for (int i = 1; i <= n; ++i)
	{
		int s;
		scanf("%d", &s);
		if (s && B && A < a)
			A = min(a, A + 1), --B;
		else if (A)
			--A;
		else
			--B;
		if (!A && !B)
			cout << i << endl, exit(0);
	}
	cout << n << endl;

	return 0;
}

E. Two Teams <數據結構> <模擬>

兩個教練選人 每次選數值最大的並且將旁邊的k個也選走 問每個人都被那個教練選走了

#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 = 2e5 + 10;
int l[N], r[N]; //左側右側編號
int a[N], b[N], c[N]; //b表示a數組從大到小編號

void sel(int x, int p) //選中x
{
	r[l[x]] = r[x], l[r[x]] = l[x]; //拼接lr
	c[x] = p; //記錄結果
}
int main()
{
#ifdef LOCAL
	//freopen("C:/input.txt", "r", stdin);
#endif
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; ++i)
		scanf("%d", &a[i]), l[i] = i - 1, r[i] = i + 1, b[i] = i;
	sort(b + 1, b + n + 1, [](int x, int y) { return a[x] > a[y]; });
	int p = 1;
	for (int i = 1; i <= n; ++i) //從大到小選取
	{
		if (c[b[i]]) //已經被選
			continue;
		int k = l[b[i]]; //兩側座標
		for (int j = 0; k && j < m; ++j)
			sel(k, p), k = l[k];
		k = r[b[i]];
		for (int j = 0; k && j < m; ++j)
			sel(k, p), k = r[k];
		sel(b[i], p);
		p = p == 1 ? 2 : 1;
	}
	for (int i = 1; i <= n; ++i)
		putchar('0' + c[i]);
	cout << endl;

	return 0;
}

寫醜了的map版

#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 = 2e5 + 10;
bool one[N]; //是否1隊

int main()
{
#ifdef LOCAL
	freopen("C:/input.txt", "r", stdin);
#endif
	map<int, int> pos, val; //位置順序 值順序
	int n, k;
	cin >> n >> k;
	for (int i = 1; i <= n; ++i)
	{
		int v;
		scanf("%d", &v);
		pos[i] = v;
		val[v] = i;
	}
	int flag = 1;
	while (!val.empty())
	{
		int p = val.rbegin()->second; //最大值位置
		for (int i = 0; i < k; ++i) //左側
		{
			auto it = pos.lower_bound(p);
			if (it == pos.begin())
				break;
			--it;
			if (flag) one[it->first] = 1;
			val.erase(it->second);
			pos.erase(it);
		}
		for (int i = 0; i < k; ++i) //右側
		{
			auto it = pos.upper_bound(p);
			if (it == pos.end())
				break;
			if (flag) one[it->first] = 1;
			val.erase(it->second);
			pos.erase(it);
		}
		if (flag) one[p] = 1;
		val.erase(pos[p]);
		pos.erase(p);
		flag ^= 1;
	}
	for (int i = 1; i <= n; ++i)
		putchar(one[i] ? '1' : '2');
	cout << endl;

	return 0;
}

F. Shovels Shop <dp> <貪心>

n個物品買k個 有m個優惠每買x個物品其中y個就免費 問最小費用
如果買k個不管有沒有優惠肯定買最便宜的k個,每個優惠策略可以重複使用所以如果同樣是買x個一個優惠y1一個優惠y2則取最大的。
購買使用優惠時肯定是將大小相近的作爲一組一起購買,因爲儘量優惠較大的。進行排序(其實找到前k小已經排序了)。
令f[i]表示購買前i個的最小代價,枚舉已經購買的物品數量嘗試使用每個優惠進行轉移取最小值。

#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 = 2e5 + 10;
int a[N], b[N], s[N];
int f[N]; //買前i個物品的最小代價

int main()
{
#ifdef LOCAL
	//freopen("C:/input.txt", "r", stdin);
#endif
	int n, m, k;
	cin >> n >> m >> k;
	for (int i = 1; i <= n; ++i)
		scanf("%d", &a[i]);
	sort(a + 1, a + n + 1); //貪心選擇儘量便宜的k個 並且dp過程中需要價值連續
	for (int i = 1; i <= k; ++i)
		s[i] = s[i - 1] + a[i]; //前綴和優化轉移
	for (int i = 0; i < m; ++i)
	{
		int x, y; //買x免費y
		scanf("%d%d", &x, &y);
		b[x] = max(b[x], y); //儘量多
	}
	memset(f, 0x3f, sizeof(f));
	f[0] = 0; //沒有物品代價0
	for (int i = 1; i <= k; ++i) //物品
		for (int j = 1; j <= i; ++j) //一次性購買量
			f[i] = min(f[i], f[i - j] + s[i] - s[i - j + b[j]]); //只花費後半部分
	cout << f[k] << endl;

	return 0;
}

G. Minimum Possible LCM <枚舉>

任選兩個數字 求最小的最小公倍數
記錄每個數字出現次數和出現下標,暴力枚舉公因子i並乘上倍數j查詢數值是否出現,如果同一個公因子i有兩個倍數j出現則計算答案並且break,因爲後面會更大。
即使是極端情況複雜度也在1e8以內。

#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 = 1e7 + 10;
int cnt[N], pos[N]; //數值出現次數 數值編號

int main()
{
#ifdef LOCAL
	//freopen("C:/input.txt", "r", stdin);
#endif
	int n;
	cin >> n;
	ll ans = LINF, p, q;
	for (int i = 1; i <= n; ++i)
	{
		int x;
		scanf("%d", &x);
		++cnt[x];
		if (cnt[x] > 1 && ans > x) //出現2次可以直接作爲答案
			ans = x, p = pos[x], q = i; //記錄上次的編號和i
		pos[x] = i;
	}
	for (int i = 1; i < N; ++i) //公約數
	{
		int k = 0; //當前公約數最小的數字的倍率
		for (int j = 1; i * j < N; ++j) //倍率
			if (cnt[i * j])
			{
				if (k) //之前已有一個
				{
					if (ans > 1LL * i * j * k) //公約數*兩個數的倍
						ans = 1LL * i * j * k, p = pos[i * k], q = pos[i * j]; //記錄編號
					break; //後面只會更大
				}
				else
					k = j; //記錄倍率
			}
	}
	if (p > q)
		swap(p, q);
	cout << p << " " << q << endl;

	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章