ABC398题解
A - Doors in the Center
问题陈述
找出满足以下所有条件的长度为 \(N\) 的字符串:
- 每个字符都是
-或=。 - 它是一个回文字符串。
- 正好包含一个或两个
=。如果包含两个=,它们是相邻的。
这样的字符串是唯一的。
解题思路
简单构造题,把 '=' 构造到中间即可,偶数时放两个,奇数时放一个。
AC代码
#include<bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
#define il inline
using namespace std;
using ll = long long;
using ull = unsigned long long;
int n;
int main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
cin>>n;
if(n&1){
for(int i = 1;i <= n/2;i++)cout<<'-';
cout<<'=';
for(int i = 1;i <= n/2;i++)cout<<'-';
}
else
{
for(int i = 1;i <= n/2-1;i++)cout<<'-';
cout<<"==";
for(int i = 1;i <= n/2-1;i++)cout<<'-';
}
return 0;
}
B - Full House 3
问题陈述
我们有七张牌。 \(i\) -th 牌 \((i=1,\ldots,7)\) 上面写着一个整数 \(A_i\) 。
请判断是否有可能从这七张牌中选择五张,使所选的牌组成葫芦。
当且仅当满足以下条件时,一组五张牌被称为葫芦:
- 对于不同的整数 \(x\) 和 \(y\) ,有三张 \(x\) 和两张 \(y\) 。
解题思路
开桶暴力统计即可,一定要先找\(\geq 3\)的,不然会被重复数。
AC代码
#include<bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
#define il inline
using namespace std;
using ll = long long;
using ull = unsigned long long;
int a[8],cnt[15];
bool flag3 , flag2;
int main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
for(int i = 1;i <= 7;i++)cin>>a[i];
for(int i = 1;i <= 7;i++)cnt[a[i]]++;
bool flag = 0;
for(int i = 1;i <= 14;i++){
if(cnt[i] >= 3){
for (int j = 1; j <= 14; j++) {
if (i != j && cnt[j] >= 2) {
flag = true;
break;
}
}
if(flag)break;
}
}
if(flag){
cout<<"Yes";
}else{
cout<<"No";
}
return 0;
}
C - Uniqueness
问题陈述
有 \(N\) 个人,标记为 \(1\) 至 \(N\) 。人 \(i\) 有一个整数 \(A_i\) 。
在满足 "其他 \(N-1\) 人中没有一个人的整数与自己相同 "条件的人中,找出整数最大的那个人,并打印这个人的标签。
如果没有人满足条件,则报告这一事实。
解题思路
开个结构体然后用\(map\)暴力统计,把计数为\(1\)的元素放到新数组,找到新数组中的最大值,输出原下标即可。
AC代码
#include<bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
#define il inline
#define inf 0x3f3f3f3f
using namespace std;
using ll = long long;
using ull = unsigned long long;
const int maxn = 3e5+10;
int n;
int a1[maxn];
int cnt;
map<int,int> mp;
struct node{
int id,v;
}a[maxn];
int main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
cin>>n;
for(int i = 1;i <= n;i++){
cin>>a1[i];
mp[a1[i]]++;
}
for(int i = 1;i <= n;i++){
if(mp[a1[i]] == 1){
a[++cnt] = {i,a1[i]};
}
}
int ans = -inf;
int res;
for(int i = 1;i <= cnt;i++){
if(a[i].v > ans){
ans = a[i].v;
res = a[i].id;
}
}
if(ans == -inf){
cout<<-1;
return 0;
}
cout<<res;
return 0;
}
D - Bonfire
问题陈述
有一个无限大的二维网格,在坐标 \((0,0)\) 处有一堆篝火。
在时间 \(t=0\) ,只有单元格 \((0,0)\) 存在烟雾。
给你一个长度为 \(N\) 的字符串 \(S\) ,由 "N"、"W"、"S"、"E "组成。在 \(t=1,2,\dots,N\) 时刻,会依次发生以下情况:
- 风吹起,当时存在的所有烟雾按如下方式移动:
- 如果 \(S\) 的 \(t\) -th 字符是 "N", \((r,c)\) 单元格中的烟雾会移动到 \((r-1,c)\) 单元格。
- 如果是 "W", \((r,c)\) 单元格中的烟雾会移动到 \((r,c-1)\) 单元格。
- 如果是 "S", \((r,c)\) 单元格中的烟雾会移动到 \((r+1,c)\) 单元格。
- 如果是 "E", \((r,c)\) 单元格中的烟雾会移动到 \((r,c+1)\) 单元格。
- 如果单元格 \((0,0)\) 中没有烟雾,则会在单元格 \((0,0)\) 中产生新的烟雾。
高桥站在 \((R,C)\) 单元格。
对于每个整数 \(1 \le t \le N\) ,判断在时间 \(t+0.5\) 时,单元格 \((R,C)\) 是否存在烟雾,并按照要求的格式打印响应。
解题思路
对于每次更改当成更改原点,用\(unordered_set\)统计即可。
AC代码
#include<bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
#define il inline
using namespace std;
using ll = long long;
using ull = unsigned long long;
ll n,r,c,dx,dy;
string s;
unordered_set<ll> vis;
il ll hs(ll x,ll y){return x << 32 | (y & 0xffffffffll);}
int main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
cin>>n>>r>>c>>s;
vis.insert(hs(0, 0));
string res;
for (char a : s) {
switch (a) {
case 'N': {dx--; break;}
case 'S': {dx++; break;}
case 'W': {dy--; break;}
case 'E': {dy++; break;}
}
ll key = hs(dx - r, dy - c);
res += vis.count(key) ? '1' : '0';
vis.insert(hs(dx, dy));
}
cout << res;
return 0;
}
E - Tree Game
问题陈述
这个问题是一个交互式问题(在这个问题中,你的程序和法官系统通过输入和输出进行交流)。
给你一棵树 \(G\) ,其中有 \(N\) 个顶点,编号为 \(1\) 至 \(N\) 。 \(i\) 这条边连接着顶点 \(U_i\) 和 \(V_i\) 。
你们将用这棵树 \(G\) 与高桥玩一个游戏。首先,你们决定谁是第一名,谁是第二名。然后,从第一位玩家开始,轮流进行以下操作:
- 选择一对满足以下两个条件的整数 \((i,j)\) 和 \(1 \leq i < j \leq N\) ,然后添加一条连接顶点 \(i\) 和 \(j\) 到 \(G\) 的边。
- \(G\) 中没有连接顶点 \(i\) 和 \(j\) 的边。
- 添加一条连接顶点 \(i\) 和 \(j\) 的边不会产生奇循环。
无法进行此操作的棋手输棋,而另一方棋手赢棋。请与高桥先生下这盘棋并获胜。
什么是奇数循环?
当且仅当满足以下所有条件时, \(G\) 的顶点 \((v_0,v_1,\ldots,v_k)\) 序列称为奇数循环:
- \(k\) 是奇数。
- \(v_0=v_k\) .
- 对于每一个 \(1\leq i \leq k\) ,都有一条边连接 \(v_{i-1}\) 和 \(v_{i}\) 。
解题思路
二分图染色后模拟。
AC代码
#include<bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
#define il inline
using namespace std;
using ll = long long;
using ull = unsigned long long;
const int maxn = 105;
const int maxm = 2e4+10;
int color[maxn];
set<pair<int, int>> e,e2,e3;
bool flag;
int k,i,j;
struct E {
int to, next;
} Edge[maxm];
int tot, Head[maxn];
inline void add(int u, int v) {
Edge[tot].to = v;
Edge[tot].next = Head[u];
Head[u] = tot++;
}
void dfs(int u, int c) {
color[u] = c;
for (int i = Head[u];~i;i = Edge[i].next) {
int v = Edge[i].to;
if (color[v] == -1) {
dfs(v, 1 - c);
}
}
}
il void solve()
{
if (flag) {
while(1){
if (e3.empty()) break;
auto it = e3.begin();
pair<int, int> ee = *it;
cout << ee.first << " " << ee.second << endl;
e3.erase(it);
cin >> i >> j;
if (i == -1 && j == -1) return;
if (i > j) swap(i, j);
e3.erase({i, j});
}
} else {
while (1) {
cin >> i >> j;
if (i == -1 && j == -1) return;
if (i > j) swap(i, j);
e3.erase({i, j});
if (e3.empty()) break;
auto it = e3.begin();
cout << it->first << " " << it->second << endl;
e3.erase(it);
}
}
}
int main() {
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
// ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
int n;cin >> n;
memset(Head,-1, sizeof(Head));
memset(color,-1, sizeof(color));
for (int i = 0; i < n - 1; ++i) {
int u, v;cin>>u>>v;
add(u, v);add(v, u);
if(u > v) swap(u, v);
e.insert({u, v});
}
dfs(1, 0);
for (int i = 1; i <= n; ++i) {
for (int j = i + 1; j <= n; ++j) {
if (color[i] != color[j]) {
auto edge = (i < j) ? make_pair(i, j) : make_pair(j, i);
if (e.find(edge) == e.end())e2.insert(edge);
}
}
}
k = e2.size();
flag = 0;
if (k == 0) {
cout<<"Second"<<endl;
return 0;
} else {
if (k & 1) {
cout<<"First"<<endl;
flag = 1;
} else {
cout<<"Second"<<endl;
}
}
e3 = e2;
solve();
return 0;
}
F - ABCBA
问题陈述
找出一个以 \(S\) 为前缀的最短回文。
解题思路
KMP的拓展应用题,用Manacher也能当板子做,找最小循环节就好。
AC代码
#include<bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
#define il inline
using namespace std;
using ll = long long;
using ull = unsigned long long;
int main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
string s;cin>>s;
int n = s.size();
string sr(s.rbegin(), s.rend());
string s2 = sr + '#' + s;
int m = s2.size();
vector<int> p(m, 0);
for (int i = 1; i < m; ++i) {
int j = p[i-1];
while (j > 0 && s2[i] != s2[j])j = p[j-1];
if (s2[i] == s2[j])j++;
p[i] = j;
}
int k = p.back();
string add = s.substr(0, n - k);
reverse(add.begin(), add.end());
string ans = s + add;
cout<<ans;
return 0;
}

浙公网安备 33010602011771号