Codeforces Round #629 (Div. 3)
A. Divisibility Problem
题意:给定两个正整数 (a,b) ,询问 (a) 最少加上多少才能整除 (b) 。
分析:略。
#include <bits/stdc++.h>
#define rep(i, a, b) for (long long i = a; i <= b; ++i)
#define SIZE 300010
#define ll long long
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
int n, m, k, t;
int main() {
io(); cin >> t;
rep(ii, 1, t) {
ll x, y;
cin >> x >> y;
ll res = ceil(1.0 * x / y);
cout << res * y - x << '
';
}
}
B. K-th Beautiful String
题意:给定两个正整数 (n,k) ,将所有由 (n-2) 个 (a) 和 (2) 个 (b) 组成的字符串按照字典序排列,求其中第 (k) 大的字符串。
分析:模拟一下即可。
#include <bits/stdc++.h>
#define rep(i, a, b) for (long long i = a; i <= b; ++i)
#define SIZE 300010
#define ll long long
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
int n, m, k, t;
int main() {
io(); cin >> t;
rep(ii, 1, t) {
cin >> n >> k;
string a(n, 'a');
int p = 2, sum = 0;
while (sum + p - 1 < k) {
sum += p - 1;
p++;
}
a[n - p] = a[n - (k - sum)] = 'b';
cout << a << '
';
}
}
C. Ternary XOR
题意:定义了一个三进制下的异或运算,给定一个三进制数 (x) ,给出一组构造满足:(a xor b=x) ,并且 (max(a,b)) 最小。
分析:简单的贪心。由于异或可以看作不进位加法,如果某一位是 (0) ,那么为了使答案最小只能是 (0+0) ;如果某一位是 (1) ,只能是 (0+1) ;如果某一位是 (2) ,那我们需要特判一下前面是否出现过某一位是 (1) 的情况,如果出现过就给出 (2+0) 的构造,如果未出现就给出 (1+1) 。
#include <bits/stdc++.h>
#define rep(i, a, b) for (long long i = a; i <= b; ++i)
#define SIZE 300010
#define ll long long
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
int n, m, k, t;
int main() {
io(); cin >> t;
rep(ii, 1, t) {
string s, a, b;
cin >> n >> s;
bool f = true;
rep(i, 0, (s.length() - 1)) {
if (s[i] == '0') a.push_back('0'), b.push_back('0');
else if (s[i] == '2') {
if (f) a.push_back('1'), b.push_back('1');
else a.push_back('0'), b.push_back('2');
}
else {
if (f) a.push_back('1'), b.push_back('0'), f = false;
else a.push_back('0'), b.push_back('1');
}
}
cout << a << '
' << b << '
';
}
}
D. Carousel
题意:给定一个数组 (a_n) ,这些数字围成了一个环。现在要求你用最少的颜色对这些数字染色并满足:相邻并取值不同的数字必须染为异色。(相邻但相同的数字随意)
分析:首先如果只有一种数字,那么只需要一种颜色。然后我们根据奇偶性不难发现:如果 (n) 是偶数,那么只要两种颜色,因为我们能够给出 (121212cdots12) 这样的构造。如果 (n) 为奇数,考虑能否将奇数转化为偶数,如果存在一组相邻的数字值相同,那我们可以将这组数看作一个数字,就转化为了偶数的情况;如果不能转化,就需要三种颜色。
#include <bits/stdc++.h>
#define rep(i, a, b) for (long long i = a; i <= b; ++i)
#define SIZE 400010
#define ll long long
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
int t, n;
int main() {
io(); cin >> t;
rep(ii, 1, t) {
cin >> n;
vector<int> vec(n);
set<int> st;
rep(i, 0, (n - 1)) cin >> vec[i], st.insert(vec[i]);
if (st.size() == 1) {
cout << "1
";
rep(i, 1, n) cout << "1 ";
}
else {
if (n % 2 == 0) {
cout << "2
";
rep(i, 1, n) cout << ((i & 1) ? "1 " : "2 ");
}
else {
int pos = -1;
rep(i, 1, n) {
if (vec[i % n] == vec[i - 1]) {
pos = i - 1;
break;
}
}
if (pos == -1) {
cout << "3
";
rep(i, 1, (n - 1)) {
if (i % 3 == 0) cout << "1 ";
else if (i % 3 == 1) cout << "2 ";
else cout << "3 ";
}
cout << (n % 3 == 1 ? 3 : 1);
}
else {
cout << "2
";
int f = 1;
rep(i, 0, (n - 1)) {
cout << (f ? "1 " : "2 ");
if (i == pos) continue;
f ^= 1;
}
}
}
}
cout << '
';
}
}
E. Tree Queries
题意:给定一棵有根树,每个询问给出一个点集 ({v_1,v_2,cdots,v_k}) ,判断是否存在一条以根节点为起点的路径使得该点集中的所有点到这条路径的距离不超过 (1) 。
分析:如果任意两个节点到他们的最近公共祖先节点的距离都不超过 (1) ,那么就满足了题意。但是不可能两两求出所有的 (LCA) ,于是考虑用最深的节点和其余节点两两求 (LCA) ,因为最深的节点到 (LCA) 的距离必定大于等于另一节点,我们只需要判断其余节点到 (LCA) 的距离是否超过了 (1) 即可。
#include <bits/stdc++.h>
#define rep(i, a, b) for (long long i = a; i <= b; ++i)
#define SIZE 400010
#define ll long long
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
int n, m, k, cnt;
int pa[SIZE][21], dep[SIZE];
vector<int> vec[SIZE]; //邻接表
void dfs(int rt, int fin) { //预处理深度和祖先
pa[rt][0] = fin;
dep[rt] = dep[pa[rt][0]] + 1; //深度
for (int i = 1; i < 21; ++i)
pa[rt][i] = pa[pa[rt][i - 1]][i - 1]; // rt 的 2^i 祖先等价于 rt 的 2^(i-1) 祖先 的 2^(i-1) 祖先
int sz = vec[rt].size();
for (int i = 0; i < sz; ++i) {
if (vec[rt][i] == fin) continue;
dfs(vec[rt][i], rt);
}
}
int LCA(int x, int y) {
if (dep[x] > dep[y]) swap(x, y);
int tmp = dep[y] - dep[x];
for (int j = 0; tmp; ++j, tmp >>= 1)
if (tmp & 1) y = pa[y][j]; //先跳到同一高度
if (y == x) return x;
for (int j = 20; j >= 0 && y != x; --j) { //从底往上跳
if (pa[x][j] != pa[y][j]) { //如果当前祖先不相等 我们就需要更新
x = pa[x][j];
y = pa[y][j];
}
}
return pa[x][0];
}
int main() {
io(); cin >> n >> m;
rep(i, 1, (n - 1)) {
int x, y; cin >> x >> y;
vec[x].emplace_back(y);
vec[y].emplace_back(x);
}
dfs(1, 0);
rep(j, 1, m) {
cin >> k;
cnt = 0;
vector<int> tmp;
int pa = 1;
rep(i, 1, k) {
int x; cin >> x;
tmp.emplace_back(x);
if (dep[x] > dep[pa]) pa = x;
}
int f = 1;
rep(i, 0, (tmp.size() - 1)) {
int fa = LCA(tmp[i], pa);
if (dep[tmp[i]] - dep[fa] > 1) {
f = false;
break;
}
}
cout << (f ? "YES
" : "NO
");
}
}
F. Make k Equal
题意:给定一个数组 (a_n) 和一个正整数 (k(kleq n)) ,每次操作能够选择数组中的一个最大数减少 (1) 或者选择一个最小数增加 (1) ,询问至少需要几次操作使得数组中至少存在 (k) 个相同元素。
分析:分类讨论一下不难发现,本题一共三种情况:只给最小值 (+1) ;只给最大值 (-1) ;同时进行两种操作。
前两种情况是本质相同的,我们只讨论情况 (1) :由贪心思想,我们必然将所有 (a_i(ileq k)) 变成 (a_k) ,然后再减去满足 (a_j=a_k(j>k)) 的数字数量(因为如果要将小于 (a_k) 的数字变成 (a_k) ,必须先将所有较小的数字变成 (a_k - 1) ,每存在一个与 (a_k) 相同的元素我们的操作数就能减少 (1) )。
对于情况 (3) ,我们不难发现,如果同时进行两种操作,那么必然要将 (a_1) 和 (a_n) 变成相等的,否则就不需要同时进行两种操作了。这说明这种情况下的最小操作数为:(sum^{frac{n}{2}}_{i=1}(a_{n-i}-a_i)-(n-k)) 。
不要忘记特判操作数为 (0) 的情况。
#include <bits/stdc++.h>
#define rep(i, a, b) for (long long i = a; i <= b; ++i)
#define ll long long
using namespace std;
void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
int n, m, k, t;
int main() {
io(); cin >> n >> k;
vector<int> a(n);
rep(i, 0, (n - 1)) cin >> a[i];
sort(a.begin(), a.end());
rep(i, 0, (n - k)) {
if (a[i] == a[i + k - 1]) {
cout << 0;
return 0;
}
}
ll ans = 0, L = 0, R = 0;
rep(i, 0, (k - 2)) L += a[k - 1] - a[i];
for (int i = n - 1; i > n - k; --i) R += a[i] - a[n - k];
rep(i, k, (n - 1)) {
if (a[i] == a[k - 1]) --L;
if (a[n - 1 - i] == a[n - k]) --R;
}
rep(i, 0, (n - 1) >> 1) ans += a[n - 1 - i] - a[i];
ans -= n - k;
cout << min(ans, min(L, R));
}