AtCoder Beginner Contest 278
A - Shift (abc278 a)
题目大意
给定一个有个整数的数组,要求进行以下 次操作,输出操作后的数组。
操作为:将第一个数去掉,在队尾加上一个。
解题思路
模拟即可。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, k; cin >> n >> k; k = min(n, k); int x; for(int i = 0; i < k; ++ i){ cin >> x; } for(int i = k; i < n; ++ i){ cin >> x; cout << x << ' '; } for(int i = 0; i < k; ++ i) cout << 0 << ' '; return 0; }
B - Misjudge the Time (abc278 b)
题目大意
定义一个迷惑时间为:交换小时的个位和分钟的十位后,所形成的时间也是有效时间。
给定一个时间,问该时间(包括该时间)之后第一个迷惑时间是多少。
解题思路
时间数就只有,逐一枚举判断即可。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int h, m; cin >> h >> m; auto check = [](int h, int m){ int h1 = h / 10; int h2 = h % 10; int m1 = m / 10; int m2 = m % 10; int H = h1 * 10 + m1; int M = h2 * 10 + m2; return H >= 0 && H <= 23 && M >= 0 && M <= 59; }; auto add = [](int &h, int &m){ ++ m; if (m >= 60){ m -= 60; h ++; } h %= 24; }; while(true){ if (check(h, m)){ cout << h << ' ' << m << '\n'; break; } add(h, m); } return 0; }
C - FF (abc278 c)
题目大意
一个聊天软件,位用户,有 次事件,第一个事件为 关注 ,第二个是取关,第三个问 和 之间是否是互关的关系。
解题思路
因为用户标号达到,不能直接二维数组,用set
或map
记录关注信息,直接判断即可。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, q; cin >> n >> q; set<pair<int, int>> qwq; while(q--){ int t, a, b; cin >> t >> a >> b; if (t == 1){ qwq.insert({a, b}); }else if (t == 2){ qwq.erase({a, b}); }else{ if (qwq.find({a, b}) != qwq.end() && qwq.find({b, a}) != qwq.end()) cout << "Yes" << '\n'; else cout << "No" << '\n'; } } return 0; }
D - All Assign Point Add (abc278 d)
题目大意
给定一个有个整数的数组,有 次操作,分为三类:
- 给定,表示将所有数赋值为
- 给定和 ,将 增加
- 给定,询问
解题思路
第一个操作相当于规定基准数,第二个操作我们用一个数组来维护增加的数,也就是相对于基准数的值。
这样对于第三个操作,就是两者的加了。
当再一次操作一时,我们把之前进行过操作二的数据对应的位置重置为即可。总的时间复杂度就是(势能分析的角度,每一次操作二会给操作一带来的势能,总的势能不超过 )
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n; cin >> n; vector<LL> a(n); set<int> id; for(int i = 0; i < n; ++ i) id.insert(i); LL base = 0; for(auto &i : a) cin >> i; int q; cin >> q; while(q--){ int op; cin >> op; if (op == 1){ for(auto &i : id){ a[i] = 0; } id.clear(); cin >> base; }else if (op == 2){ int pos; LL val; cin >> pos >> val; -- pos; a[pos] += val; id.insert(pos); }else { int pos; cin >> pos; -- pos; cout << base + a[pos] << '\n'; } } return 0; }
E - Grid Filling (abc278 e)
题目大意
给定一个矩形,格子上有数。
给定,意味大小为的黑布,该黑布从矩形左上角向右移动,向下移动,直到右下角。问每个位置,将黑布的数遮盖后,剩下未被遮盖的不同的数的个数。
解题思路
暴力即可,黑布往右移动的时候,加上被遮住的一列,减去被遮住的一列。总的时间复杂度为
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int H, W, N, h, w; cin >> H >> W >> N >> h >> w; vector<vector<int>> a(H, vector<int>(W)); vector<int> cnt(N + 1, 0); int ans = 0; for(auto &i : a) for(auto &j : i){ cin >> j; cnt[j] ++; if (cnt[j] == 1) ++ ans; } vector<int> tmp(cnt.begin(), cnt.end()); int bac = ans; for(int i = 0; i <= H - h; ++ i){ for(int j = i; j < i + h; ++ j) for(int k = 0; k < 0 + w; ++ k){ cnt[a[j][k]] --; if (cnt[a[j][k]] == 0) -- ans; } cout << ans; for(int j = 1; j <= W - w; ++ j){ for(int k = i; k < i + h; ++ k){ cnt[a[k][j - 1]] ++; if (cnt[a[k][j - 1]] == 1) ++ ans; } for(int k = i; k < i + h; ++ k){ cnt[a[k][j + w - 1]] --; if (cnt[a[k][j + w - 1]] == 0) -- ans; } cout << ' ' << ans; } cout << '\n'; ans = bac; cnt = tmp; } return 0; }
也可以记录一个二维前缀和表示 的矩形中,数字 出现的次数。然后对于每次询问通过前缀和得到剩下各个数字出现的次数,再检查非的个数。复杂度也是 ,且这种更好写一点。
F - Shiritori (abc278 f)
题目大意
给定个字符串, 和 在玩。 先手。
每个人说出一个~数字,该数字必须是之前未说过的,且的首字母和的尾字母相同,其中 是上一个人说过的数字。
问两者都是绝顶聪明的情况下,谁赢。
解题思路
设表示目前已经选择的数字状态为 ,且最后说过的数字是 ,当前状态是必胜还是必输,枚举后继状态,直接搜索即可。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n; cin >> n; vector<vector<int>> edge(n); vector<pair<int, int>> qwq; for(int i = 1; i <= n; ++ i){ string s; cin >> s; qwq.push_back({s.front(), s.back()}); } for(int i = 0; i < n; ++ i) for(int j = 0; j < n; ++ j){ if (i == j) continue; if (qwq[i].second == qwq[j].first) edge[i].push_back(j); } vector<vector<int>> dp((1 << n), vector<int>(n, -1)); function<int(int, int)> dfs = [&](int s, int la){ if (dp[s][la] != -1) return dp[s][la]; int ok = 1; for(auto nxt : edge[la]){ if ((s >> nxt) & 1) continue; ok &= dfs(s | (1 << nxt), nxt); } return dp[s][la] = (ok ^ 1); }; int ok = 1; for(int i = 0; i < n; ++ i){ ok &= dfs((1 << i), i); } if (!ok) cout << "First" << '\n'; else cout << "Second" << '\n'; return 0; }
G - Generalized Subtraction Game (abc278 g)
题目大意
有写有数字~的牌放在桌子上,给定,你和一个绝顶聪明的人玩一个游戏。你可以选择你先手还是后手,然后轮流进行的操作是:
- 选择一个连续区间,其长度在内。然后将桌子上该区间的数字牌全部拿走。注意必须区间上的所有数字牌都在桌子上。
谁无法操作就输。
请写一个程序,打赢这个绝顶聪明的人。
解题思路
蛮有意思的交互题,是一场真·博弈对决。
第一次操作相当于将一个连续的区间一分为二,可以考虑一种经典策略:对称操作。如果将区间分成两个一模一样,那么对方对区间做的操作,我都可以对区间 做同样的操作。这样一定是对方最先变得无法操作。
将 拆成 ,其中中间那个是丢掉的,很显然中间的区间数量的奇偶性和相同(前后两个区间内数量加起来必是偶数)。因此当 且 与 奇偶性相等 时,或者时(此时 和 必定有个与 奇偶性相同)都可以采用此策略:选择先手,将区间拆成两个相等的,然后模仿对方行为做即可。
但当 且 与 的奇偶性不相等时,此时我们考虑暴力了。
该题本质上还是博弈题。当我们对一个区间一分为二后,新出来的两个区间本质上就是两个独立的游戏,因此此时游戏的值就是这两个区间的 值的异或。
因此我们求得所有长度的值,先根据初态是必胜态还是必败态选择先后手,然后枚举选择一种操作使得下一个局面是必败态(对方必败)。
预处理值的复杂度是 ,即枚举当前长度,然后枚举操作起点(操作长度是固定的为 )。
后来枚举下一步操作的复杂度是 。
事实上 的话,两者的复杂度都要乘以 。不过有人说可以在的时间内预处理,每次操作的复杂度是
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, l, r; cin >> n >> l >> r; if (r - l >= 1 || ((l & 1) == (n & 1))){ int op = l + ((l & 1) != (n & 1)); int left = (n - op) >> 1; cout << "First" << endl; cout << left + 1 << ' ' << op << endl; int x, y; while(true){ cin >> x >> y; if (x == 0 || x == -1) break; if (x <= left){ cout << x + left + op << ' ' << y << endl; }else { cout << x - left - op << ' ' << y << endl; } } }else{ vector<int> sg(n + 1, 0); vector<int> cnt(n + 5, 0); for(int i = 1; i <= n; ++ i){ for(int j = 1; j <= i; ++ j){ if (j + l - 1 > i) break; cnt[sg[j - 1] ^ sg[i - (j + l - 1)]] = 1; } int val = 0; while(cnt[val]) ++ val; sg[i] = val; fill(cnt.begin(), cnt.end(), 0); } set<pair<int, int>> s; s.insert({1, n}); int cur = sg[n]; auto work = [&](){ for(auto &c : s){ for(int i = c.first; i <= c.second; ++ i){ if (i + l - 1 > c.second) break; int nxt = cur ^ sg[c.second - c.first + 1] ^ sg[i - c.first] ^ sg[c.second - (i + l - 1)]; if (!nxt) return i; } } return 0; }; auto remove = [&](int pos){ for(auto &c : s){ if (pos >= c.first && pos <= c.second){ cur ^= sg[c.second - c.first + 1] ^ sg[pos - c.first] ^ sg[c.second - (pos + l - 1)]; s.insert({c.first, pos - 1}); s.insert({pos + l, c.second}); s.erase(c); return; } } }; if (sg[n]){ cout << "First" << endl; int pos = work(); cout << pos << ' ' << l << endl; remove(pos); }else{ cout << "Second" << endl; } while(true){ int x, y; cin >> x >> y; if (x == 0 || x == -1) break; remove(x); int pos = work(); cout << pos << ' ' << l << endl; remove(pos); } } return 0; }
Ex - make 1 (abc278 h)
题目大意
<++>
解题思路
<++>
神奇的代码
本文作者:~Lanly~
本文链接:https://www.cnblogs.com/Lanly/p/16907585.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步