Codeforces Round #653 (Div. 3)题解

Codeforces Round #653 (Div. 3)

A.Required Remainder

题目大意

给你x,y,n,问你最大的k(1 <= k <= n)满足k mod x = y是多少

解题思路

k = x * m + y <= n
m <= (n - y) / x
那么max(k) = [(n - y) / x] * x + y

AC代码

#include 
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while (T--) {
		ll x, y, n;
		cin >> x >> y >> n;
		cout <<(n - y) / x * x + y << '\n';
	}
	return 0;
}

B.Multiply by 2, divide by 6

题目大意

给你一个n,每次你可以将他乘以2或者除以6(如果n % 6 == 0),问你n到达1的最少次数是多少,如果无法到达,输出-1

解题思路

n * 6 -x * 2y = 1
n = 3x * 2x-y
num = x + y = 2 * x - (x - y)
所以将n分解为x个3相乘和x - y个2相乘即可
无法分解或者出现x > x - y表示num = -1

AC代码

#include 
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int t;
	cin >> t;
	while (t--) {
		int n;
		cin >> n;
		int x = 0, xy = 0;
		while (n % 3 == 0) {
			++x;
			n /= 3;
		}
		while (n % 2 == 0) {
			++xy;
			n /= 2;
		}
		int num = n == 1 && x >= xy ? 2 * x - xy : -1;
		cout << num << '\n';
	}
	return 0;
}

C.Move Brackets

题目大意

给你一个由’(‘和’)'组成的字符串,每次你可以把一个字符移动到字符串头部或尾部,问你多少次后字符串合法,保证答案存在

解题思路

用栈对括号进行匹配,剩下的无法匹配的字符中’('的个数即为答案

AC代码

#include 
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while (T--) {
		int n;
		cin >> n;
		string s;
		cin >> s;
		stack<char> que;
		for (int i = 0; i < n; ++i) {
			if (que.empty() || s[i] == '(') {
				que.push(s[i]);
			}
			else if (s[i] == ')') {
				if (!que.empty() && que.top() == '(') que.pop();
				else que.push(s[i]);
			}
		}
		int a = 0, b = 0;
		while (!que.empty()) {
			if (que.top() == '(') ++a;
			else ++b;
			que.pop();
		}
		cout << min(a, b) << '\n';
	}
	return 0;
}

D.Zero Remainder Array

题目大意

给你一个长度为n的数组a和数k,每次你可以选择一下两个操作中的一个,x初值为0:

  1. 选择一个数a[i]执行a[i] = a[i] + x, x = x + 1
  2. 执行x = x + 1

问你多少次后数组中的数都可以被k整除

解题思路

考虑由于x是在不停增加的,如果k - a[i] % k == k - a[j] % k,那么要想使得a[i]和a[j]同时达成条件,x需要在a[i]变成k的倍数后继续增加k然后加到a[j]上使得a[j]也变成k的倍数,那么答案已经呼之欲出了,我们将所有的a[i]变成k - a[i] % k(如果a[i] % k == 0就将其忽略),找到其中出现最多的那个数,假设为Max,出现次数为cnt(Max),那么我们需要将所有的Max变的满足条件,就需要(cnt(Max) - 1) * k + Max + 1次(加一是因为x初值为0),在这期间其余的所有数均有对应的x使其变成k的倍数(可以自己证明或者模拟一下),所以答案即为(cnt(Max) - 1) * k + Max + 1

AC代码

#include 
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
int a[maxn];
map<int, int> mp;
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	register int T;
	cin >> T;
	while (T--) {
		register ll n, k;
		cin >> n >> k;
		register ll Max = 0;
		mp.clear();
		for (register int i = 1; i <= n; ++i) {
			cin >> a[i];
			if (a[i] % k == 0) {
				a[i] = 0;
				continue;
			}
			a[i] = a[i] / k * k + k - a[i];
			++mp[a[i]];
			if (mp[Max] < mp[a[i]]) Max = a[i];
			else if (mp[Max] == mp[a[i]] && a[i] > Max) Max = a[i];
		}
		if (mp.empty()) {
			cout << "0\n";
			continue;
		}
		register ll res = Max + (mp[Max] - 1) * k + 1;
		cout << res << '\n';
	}
	return 0;
}

E1. Reading Books (easy version)

题目大意

Bob和Alice有n本书要阅读,每本书的阅读时间为t[i],其中有的书只有Bob喜欢,有的书只有Alice喜欢,有的书他们都喜欢,你要从里面挑一些书让他们共同阅读,并保证其中至少有k本Alice喜欢,有k本Bob喜欢,问你最小的阅读时间是多少

解题思路

将书分成三类
a[i]记录Bob喜欢的书的阅读时间
b[i]记录Alice喜欢的书的阅读时间
c[i]记录他们都喜欢的书的阅读时间
假设现在从a中挑x本,从b中挑y本,从c中挑z本
那么其需要满足的条件为:
x + z >= k
y + z >= k
显然在等号处取得最优解
所以x = y
即解集中Bob和Alice单独喜欢的书的数量相同
那么我们将三个数组按时间大小排序,枚举x即可

AC代码

#include 
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
int a[maxn], b[maxn], c[maxn], d[maxn];
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int n, k;
	cin >> n >> k;
	int cnta = 0, cntb = 0, cntc = 0;
	for (int i = 1; i <= n; ++i) {
		int t, x, y;
		cin >> t >> x >> y;
		if (x && y) {
			c[++cntc] = t;
		}
		else if (x) a[++cnta] = t;
		else if (y) b[++cntb] = t;
	}
	if (cnta + cntc < k || cntb + cntc < k) {
		cout << "-1\n";
		return 0;
	}
	sort(a + 1, a + cnta + 1);
	sort(b + 1, b + cntb + 1);
	sort(c + 1, c + cntc + 1);
	for (int i = 1; i <= cntc; ++i) d[i] = d[i - 1] + c[i];
	int res = 0, Min = 0x7fffffff;
	int len = min(k, min(cnta, cntb));
	for (int i = 1; i <= len; ++i) {
		res += a[i] + b[i];
		if (!d[k - i] && i != k) continue;
		Min = min(Min, res + d[k - i]);
	}
	if (d[k]) Min = min(Min, d[k]);
	cout << Min << '\n';
	return 0;
}

你可能感兴趣的:(codeforces)