- 2026 SYNU 五月周赛 Round III (Div 3)
题解
- @ 2026-5-22 20:18:43
五月第四次周赛题解
乒乓球
思路
把输入中的所有 W / L 按顺序读入,遇到 E 立刻停止。
然后分别模拟:
11分制21分制
对于当前局维护两个人的分数 a, b:
W则a++L则b++- 当
max(a,b) >= limit且abs(a-b) >= 2时,这一局结束,输出并清零
最后别忘了输出当前未结束那一局的比分。
复杂度
- 时间复杂度:
O(n) - 空间复杂度:
O(n),其中n是读入的总字符数
参考代码
#include <bits/stdc++.h>
using namespace std;
vector<string> work(const string &s, int lim) {
int a = 0, b = 0;
vector<string> ans;
for (char ch : s) {
if (ch == 'W') ++a;
else ++b;
if (max(a, b) >= lim && abs(a - b) >= 2) {
ans.push_back(to_string(a) + ":" + to_string(b));
a = b = 0;
}
}
ans.push_back(to_string(a) + ":" + to_string(b));
return ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
string s;
char ch;
while (cin >> ch) {
if (ch == 'E') break;
s += ch;
}
auto a = work(s, 11);
auto b = work(s, 21);
for (auto &x : a) cout << x << '\n';
cout << '\n';
for (auto &x : b) cout << x << '\n';
return 0;
}
搞快点搞快点
思路
设 dp[k][x] 表示:
- 当前还剩
k层蛋仔塔 - 塔底端位于位置
x - 此时让最上方蛋仔
D继续到终点的最小已花费时间
初始状态是 dp[4][0] = 0。
转移分两种:
-
普通前进
从x到x+1,代价是第x+1段路的耗时。 -
超级弹射
若当前有k >= 2层,那么最下方蛋仔消失,其余k-1层被弹到min(l, x+d),耗时0。
因为所有移动都只会让位置变大,所以每一层的普通前进直接从左到右扫一遍即可。
顺序是:
- 先处理
4层的前进,再从4层弹到3层 - 再处理
3层的前进,再弹到2层 - 再处理
2层的前进,再弹到1层 - 最后处理
1层前进到终点
答案是 dp[1..4][l] 的最小值。
复杂度
- 时间复杂度:
O(l) - 空间复杂度:
O(l)
参考代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = (ll)4e18;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int l, d;
cin >> l >> d;
ll t0, t1, t2;
cin >> t0 >> t1 >> t2;
string s;
cin >> s;
vector<ll> cost(l + 1);
for (int i = 1; i <= l; ++i) {
if (s[i - 1] == '0') cost[i] = t0;
else if (s[i - 1] == '1') cost[i] = t1;
else cost[i] = t2;
}
vector<vector<ll>> dp(5, vector<ll>(l + 1, INF));
dp[4][0] = 0;
for (int k = 4; k >= 2; --k) {
for (int x = 0; x < l; ++x) {
if (dp[k][x] == INF) continue;
dp[k][x + 1] = min(dp[k][x + 1], dp[k][x] + cost[x + 1]);
}
for (int x = 0; x <= l; ++x) {
if (dp[k][x] == INF) continue;
int to = min(l, x + d);
dp[k - 1][to] = min(dp[k - 1][to], dp[k][x]);
}
}
for (int x = 0; x < l; ++x) {
if (dp[1][x] == INF) continue;
dp[1][x + 1] = min(dp[1][x + 1], dp[1][x] + cost[x + 1]);
}
ll ans = min({dp[1][l], dp[2][l], dp[3][l], dp[4][l]});
cout << ans << '\n';
return 0;
}
来打uno吗
思路
目标状态要求:
- 颜色顺序是
R < Y < G < B - 同色内部点数非递减
允许交换的条件是:相邻两张牌同色,或者同点数。
关键观察:
- 同色的两张牌,最终内部顺序可以调整
- 同点数的两张牌,也可以互相跨过去
- 但是如果两张牌 颜色不同且点数不同,那么它们之间永远不可能直接交换
因此:
如果在当前序列中,存在一张更靠前的牌 A 和一张更靠后的牌 B,满足:
A的颜色应该排在B后面- 并且
A与B点数不同
那么这对相对顺序无法修复,答案一定是 NO。
我们从左到右扫描每张牌 (x, c),统计前面已经出现过多少张更高颜色的牌;
但如果那些牌与当前牌点数相同,则它们是可以通过“同点数交换”跨过去的,不算坏对。
于是只要检查:
前面更高颜色的牌数 - 前面更高颜色且同点数的牌数
是否大于 0 即可。
复杂度
- 时间复杂度:
O(4n) - 空间复杂度:
O(4n)
参考代码
#include <bits/stdc++.h>
using namespace std;
#define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define int long long
typedef vector<vector<int>> mat;
using pii = pair<int, int>;
using pdd = pair<double,double>;
constexpr int N = 2e5 + 10;
void solve()
{
int n;cin>>n;
vector<int> a(n*4+10);
vector<char> b(n*4+10);
map<char,int> mp;
mp['R']=1;mp['Y']=2;mp['G']=3;mp['B']=4;
for(int i=1;i<=n*4;i++) cin>>a[i]>>b[i];
for(int i=1;i<=n*4;i++)
for(int j=i;j<=n*4;j++)
{
if(mp[b[i]]>mp[b[j]]&& a[i]!=a[j])
{
cout<<"NO\n";
return;
}
}
cout<<"YES\n";
return;
}
signed main()
{
IOS;
int _= 1;
cin >> _;
while(_--)
{
solve();
}
return 0;
}
马拉松的困难
思路
题目要求判断 N 是否能整除 M,也就是判断:
M % N == 0
成立则输出 1,否则输出 0。
复杂度
- 时间复杂度:
O(T) - 空间复杂度:
O(1)
参考代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int M, N;
cin >> M >> N;
cout << (M % N == 0 ? 1 : 0) << '\n';
}
return 0;
}
0 条评论
目前还没有评论...