【比赛】ARC136|220227
A - A ↔ BB
考虑一些贪心的事实:
- 如果有连着的
BB
,换成A
显然更优 - 如果有连着的
BA
,可以换成AB
更优 - 如果连着的是其他字符,不管最优
#include <bits/stdc++.h>
using namespace std;
int n;
deque<char> s;
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
cin >> n;
char c;
for(int i = 1; i <= n; i++) {
cin >> c;
s.push_back(c);
}
while(!s.empty()) {
if(s.size() > 1) {
char p = *s.begin(), q = *(next(s.begin()));
if(p == 'B' && q == 'A') {
s.pop_front(), s.pop_front();
s.push_front('B'), s.push_front('A');
} else if(p == 'B' && q == 'B') {
s.pop_front(), s.pop_front();
s.push_front('A');
}
}
cout << s.front();
s.pop_front();
}
return 0;
}
B - Triple Shift
Des
给定长度为 的数组 和 ,每次可以选定 中连续的三个数,然后把三个数 换为 。问能不能经过若干次操作把 成 .
Sol
怎么又是这种交换 + 逆序对题,USACO 铜组才考。
发现是把一个数隔着前面的一个数往前调(三元组前调?),调换之后一定不会改变逆序对的奇偶性。所以直接统计逆序对个数,奇数就不行,偶数就行。
但是你会发现有相等的元素。如果越过了一个相等的元素,那么逆序对个数的奇偶性可能会改变?考虑给相等的元素强行定一个排名,然后如果逆序对个数是奇数的话,就交换两个相等的元素,逆序对个数就会变成偶数。所以只要存在相等的元素就一定有解。
My Code
#include <bits/stdc++.h>
using namespace std;
const int N = 5005;
int n, p[N], oa[N];
struct wtf {
int v, id;
} a[N], b[N];
int main() {
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i].v, a[i].id = i, oa[i] = a[i].v;
for(int i = 1; i <= n; i++) cin >> b[i].v, b[i].id = i;
auto cmp = [&](wtf x, wtf y) {
return x.v < y.v;
};
sort(a + 1, a + n + 1, cmp);
sort(b + 1, b + n + 1, cmp);
for(int i = 1; i <= n; i++) {
if(a[i].v != b[i].v) {
cout << "No\n";
return 0;
}
}
for(int i = 1; i <= n; i++)
p[a[i].id] = b[i].id;
int tot = 0;
for(int i = 1; i <= n; i++) {
debug(i, p[i]);
for(int j = i + 1; j <= n; j++) {
if(oa[i] == oa[j]) {
cout << "Yes\n";
return 0;
}
if(p[i] > p[j]) ++tot;
}
}
if(tot & 1) cout << "No\n";
else cout << "Yes\n";
return 0;
}
C - Circular Addition
Des
环上排着 个数 ,每次可以选择任意一个区间,把区间内的数都减一。问把所有数都减成 需要的最小操作次数。
Sol
考场上想了个把积木大赛 套进去的假做法,亏惨了。
正解比较妙,不如考场多弄几个样例猜结论。
考虑差分数组 ( 数组下标从 0 开始),然后设 , 那么答案等于 。
首先答案至少需要这个数量的操作,因为每次最多把最大值减少一, 减少二,而 .
然后证可以在这个数量内操作完毕。
首先考虑 的情况,可以证明的是这种情况下不存在 ,因为考虑到 的这个环会使得 ,矛盾了。于是就可以不断给所有数减一直到 .
然后考虑 的情况。每次可以选择一个「最大的」包含 的区间,把这个区间减一(这里没看懂怎么就能一直给 减一了,但是可以考虑每次选择一个区间,保证这个区间外面左边和右边的数分别比区间里面左边和右边的数小,应该是能选到的)。
最后考虑 的情况。如果只有一个 ,选择最大的包含 的区间减一就能让 同时减一。如果有多个 ,则一定不存在 的情况(考虑 仍然可以得证)。所以可以选择一个最大的包含所有 的区间减一,也能让 同时减一。
这样就完成证明了,时间复杂度 .
My Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
int n;
ll ans;
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
cin >> n;
ll M = 0, D = 0;
vector<int> a;
for(int i = 1, t; i <= n; i++) {
cin >> t;
a.emplace_back(t);
M = max(M, (ll)t);
}
for(int i = 0; i < (int)a.size(); i++)
D += abs(a[i] - a[(i - 1 + n) % n]);
D /= 2;
cout << max(M, D) << '\n';
return 0;
}
D - Without Carry
Des
给定 个数,求使得 做竖式加法不进位,且 成立的二元组 的个数。
Sol
考场上觉得比 C 题简单但是不会做,以为是容斥结果不行。然后想到可能是一个多维的前缀和,但是不会构建,卒。
可以看一下 CF 讨论里某好心人教的高维前缀和构建方法 。我就不写了。
设 ,复杂度是 。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, j, k) for(int i = j; i <= k; i++)
const int N = 1e6 + 5;
int n, a[N], p[10];
int s[11][11][11][11][11][11];
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i];
for(int x = a[i], j = 1; j <= 6; j++, x /= 10) p[j] = x % 10 + 1;
++s[p[1]][p[2]][p[3]][p[4]][p[5]][p[6]];
}
rep(w, 1, 6)
rep(i1, 1, 10)
rep(i2, 1, 10)
rep(i3, 1, 10)
rep(i4, 1, 10)
rep(i5, 1, 10)
rep(i6, 1, 10)
s[i1][i2][i3][i4][i5][i6] += s[i1 - (w == 1)][i2 - (w == 2)][i3 - (w == 3)][i4 - (w == 4)][i5 - (w == 5)][i6 - (w == 6)];
long long ans = 0;
for(int i = 1; i <= n; i++) {
bool flag = true;
for(int x = a[i], j = 1; j <= 6; j++, x /= 10) p[j] = x % 10, flag &= (p[j] < 5);
ans += s[10 - p[1]][10 - p[2]][10 - p[3]][10 - p[4]][10 - p[5]][10 - p[6]];
ans -= flag;
}
ans /= 2;
cout << ans << '\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构