比赛链接:
https://codeforces.com/gym/103427
https://ac.nowcoder.com/acm/contest/24346
B. Bitwise Exclusive-OR Sequence
题意:
给定 \(m\) 个限制,要求构造一个全是非负整数的序列 \(a\),每个限制告诉 \(u, v, w\),要求满足 \(a_u\) ^ \(a_v\) = \(w\),如果能构造出来,要求输出构造出的 \(a\) 序列的所有元素总和的最小值,否则输出 -1。
思路:
可以构建一个图,让 \(u, v\) 之间有一条权重为 \(w\) 的边。接着对整个图进行染色,对于一个数字,每一位只可能是 0 或者 1,选择一个未染色的点(记为起点)将它标为 0,即该点每一位都是 0,修改所有连通的点,如果有不符合限制的点出现,输出 -1,否则可以染好颜色。
对于每一位,只可能有两种情况,刚开始将起点染为了 0,另一种情况就是起点为 1,两种情况取一个 1 少的,即是该位上之和的最小值。
代码:
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(){
ios::sync_with_stdio(false);cin.tie(0);
int n, m;
cin >> n >> m;
vector < vector < pair <int, int> > > e(n + 1);
for (int i = 0; i < m; i ++ ){
int u, v, w;
cin >> u >> v >> w;
e[u].push_back({w, v});
e[v].push_back({w, u});
}
LL ans = 0;
vector <int> c(n + 1, -1);
for (int i = 1; i <= n; i ++ ){
if (c[i] == -1){
vector <int> a;
function<void(int)> dfs = [&](int u){
a.push_back(c[u]);
for (auto [w, v] : e[u]){
if (c[v] == -1){
c[v] = c[u] ^ w;
dfs(v);
}
else if ((c[u] ^ c[v]) != w){
cout << "-1\n";
exit(0);
}
}
};
c[i] = 0;
dfs(i);
for (int i = 0; i < 30; i ++ ){
LL cnt = 0;
for (auto j : a)
cnt += (j >> i) & 1;
ans += min(cnt, (LL)a.size() - cnt) * (1 << i);
}
}
}
cout << ans << "\n";
return 0;
}
E. Edward Gaming, the Champion
题意:
给定字符串,求 "edgnb" 子串出现的数量。
思路:
按题意模拟。
代码:
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);cin.tie(0);
string s;
cin >> s;
int cnt = 0;
for (int i = 0; i < (int)s.size() - 4; i ++ )
cnt += (s.substr(i, 5) == "edgnb");
cout << cnt << "\n";
return 0;
}
F. Encoded Strings I
题意:
定义 \(F(c) = chr(G(c, s))\),\(G(c, s)\) 表示在字符串 \(s\) 中最后一个 \(c\) 位置之后有几个不同的字母,\(chr(i)\) 表示第 \(i + 1\) 个字母,现在给定一个字符串,问它的所有前缀通过 \(F(c)\) 转化后的最大字典序是什么。
思路:
直接暴力跑出所有前缀转化后的字符串,然后排个序就行。
代码:
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);cin.tie(0);
int n;
cin >> n;
string s;
cin >> s;
auto get = [&](string t){
vector <int> pos(26, -1);
int m = t.size(), cnt = 0;
for (int i = m - 1; i >= 0; i -- ){
if (pos[t[i] - 'a'] != -1) continue;
pos[t[i] - 'a'] = (cnt ++ );
}
string ans = "";
for (int i = 0; i < m; i ++ )
ans = ans + (char)('a' + pos[t[i] - 'a']);
return ans;
};
vector <string> a;
for (int i = 1; i <= n; i ++ )
a.push_back(get(s.substr(0, i)));
sort(a.begin(), a.end());
cout << a[n - 1] << "\n";
return 0;
}
J. Luggage Lock
题意:
有一个四位数的密码锁,每次可以将连续的几位同时向上或者向下转动,现在有 \(q\) 次询问,问将密码锁从 \(a\) 状态变成 \(b\) 状态最少需要几步。
思路:
通过 \(bfs\) 预处理出所有情况,然后每次 \(O(1)\) 回答询问即可。
代码:
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);cin.tie(0);
vector <int> d(10000, -1);
d[0] = 0;
auto bfs = [&](){
queue <int> q;
q.push(0);
while(!q.empty()){
auto u = to_string(q.front());
q.pop();
while((int)u.size() < 4) u = '0' + u;
for (int i = 0; i < 4; i ++ ){
for (int j = i; j < 4; j ++ ){
auto t = u;
for (int k = i; k <= j; k ++ )
t[k] = (t[k] - '0' + 1) % 10 + '0';
if (d[stoi(t)] == -1){
d[stoi(t)] = d[stoi(u)] + 1;
q.push(stoi(t));
}
t = u;
for (int k = i; k <= j; k ++ )
t[k] = (t[k] - '0' + 9) % 10 + '0';
if (d[stoi(t)] == -1){
d[stoi(t)] = d[stoi(u)] + 1;
q.push(stoi(t));
}
}
}
}
};
bfs();
int T;
cin >> T;
while(T -- ){
string a, b;
cin >> a >> b;
for (int i = 0; i < 4; i ++ )
b[i] = (b[i] - a[i] + 10) % 10 + '0';
cout << d[stoi(b)] << "\n";
}
return 0;
}