The 3rd Universal Cup. Stage 16: Nanjing
B. Birthday Gift
把原始串的偶数位取反,题目从消除相同就可以转换为消除不同。因此只要有不同位,就一定可以消除。因此最终剩下的串一定是全 0 或者全 1。因此答案就是翻转后的 1、0 之差。我们用 2 尽可能的减少0,1 只差即可。
#include <bits/stdc++.h>
#define ll long long
void solve() {
std::string s;
std::cin >> s;
int cnt0 = 0, cnt1 = 0, cnt2 = 0;
for(int x, y = 0; auto c : s) {
x = c - '0';
if(x == 2) cnt2 ++;
else {
x ^= y;
if(x == 0) cnt0 ++;
else cnt1 ++;
}
y ^= 1;
}
int ans = abs(cnt0 - cnt1) - cnt2;
if(ans < 0) ans = (-ans) % 2;
std::cout << ans << "\n";
return;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
while (t--){
solve();
}
return 0;
}
E. Left Shifting 3
循环位移只能把首尾连起来。额外计算一下首尾拼起来能不能构成nanjing
。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using vi = vector<int>;
using pii = pair<int,int>;
const string t = "nanjing";
void solve() {
int n, k;
cin >> n >> k;
string s;
cin >> s;
int res = 0;
for(int i = 0; i + 6 < n; i ++)
if(s.substr(i, 7) == t) res ++;
for(int i = 1; i <= min(k, 6) and n >= 7; i ++){
if(s.substr(n - 7 + i, 7 - i) + s.substr(0, i) == t) {
res ++;
break;
}
}
cout << res << "\n";
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while(T --)
solve();
return 0;
}
J. Social Media
一条评论,可以当成一条无向边。边一共有三种。
- 两个端点都被选择
- 一个端点被选择
- 两端点都没有被选择
对于第一种边直接累计到到答案中,对于第二种边统计没有被选择的边链接了多少条边,对于第三种边,加入到图中。
多选点不会使得答案更差。因此一定要选两个点。
首先我们枚举第一点个,第一个被选择后,第二种边就会转换为第一种边。第一个点所连接的第三种边都会转换为第二种边。对于第二个点,贪心的选择 第二种边最多的。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using vi = vector<int>;
using pii = pair<int,int>;
void solve() {
int n, m, k;
cin >> n >> m >> k;
vector<bool> selected(k + 1);
for(int i = 1, x; i <= n; i ++) {
cin >> x;
selected[x] = true;
}
int ans = 0;
vi cnt(k + 1), cnt2(k + 1);
vector<vi> e(k + 1);
for(int i = 1, x, y; i <= m; i ++) {
cin >> x >> y;
if(selected[x] and selected[y]) ans ++;
else if(selected[x]) cnt[y] ++;
else if(selected[y]) cnt[x] ++;
else if(x == y) cnt[x] ++;
else e[x].push_back(y), e[y].push_back(x);
}
int max1 = 1, max2 = 2;
if(cnt[max2] > cnt[max1]) swap(max1, max2);
for(int i = 3; i <= k; i ++) {
if(cnt[i] > cnt[max1] ) max2 = max1, max1 = i;
else if(cnt[i] > cnt[max2]) max2 = i;
}
int res = 0;
for(int i = 1, ret; i <= k; i ++) {
if(selected[i]) continue;
if(i == max1) ret = max2;
else ret = max1;
for(auto y : e[i]) {
cnt2[y] ++;
if(cnt[y] + cnt2[y] > cnt[ret] + cnt2[ret]) ret = y;
}
res = max(res, cnt[i] + cnt[ret] + cnt2[ret]);
for(auto y : e[i]) cnt2[y] = 0;
}
cout << ans + res << "\n";
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while(T --)
solve();
return 0;
}
K. Strips
按照黑色点分段。分段对坐标进行映射到 1 到 n。
我们从左到右,贪心的选择最靠右的区间。这样一定可以保证使用区间数量最少。
然后我们检查最右侧的区间是否越界。如果越界就要把最右侧的区间的和有段点对齐。对齐后如果左侧碰到了区间就要逐个把区间向左推。如果最左侧的区间依旧越界,就是无解。否则就是一种答案。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
using pii = pair<int,int>;
void solve() {
int n, m, k, w;
cin >> n >> m >> k >> w;
vi r(n);
for(int i = 0; i < n; i ++)
cin >> r[i];
vi b(m);
for(int i = 0; i < m; i ++)
cin >> b[i];
b.push_back(0), b.push_back(w + 1);
ranges::sort(r);
ranges::sort(b);
auto calc = [k](int n, vi a) -> vi {
vi l , r;
for(auto i : a) {
if(r.empty() or i > r.back()){
l.push_back(i);
r.push_back(i + k - 1);
}
}
int R = n;
for(int i = l.size() - 1; i >= 0; i --) {
if(r[i] <= R) break;
r[i] = R;
l[i] = R - k + 1;
R = l[i] - 1;
}
if(l[0] >= 1) return l;
else return vi();
};
vi res, cur;
for(int i = 0, j = 0; i + 1 < b.size() and j < n; i ++) {
cur = vi();
while(j < n and b[i] < r[j] and r[j] < b[i + 1])
cur.push_back(r[j] - b[i]), j ++;
if(cur.empty()) continue;
auto ret = calc(b[i + 1] - b[i] - 1, cur);
if(ret.empty()) {
cout << -1 << "\n";
return;
}
for(auto x : ret)
res.push_back(x + b[i]);
}
cout << res.size() << "\n";
for(auto i : res) assert(1 <= i <= w - k + 1 ), cout << i << " ";
cout << "\n";
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while(T --)
solve();
return 0;
}