Educational Codeforces Round 166(A-D题解)
Educational Codeforces Round 166(A-D题解)
Educational Codeforces Round 166
2024-06-03 —yimg
A
签到题
代码:
#include<bits/stdc++.h>
using namespace std;
void work()
{
int n;
cin >> n;
string s;
cin >> s;
int pos = 0;
int g = 1;
for(; pos < s.length(); ++pos){
if(s[pos] >= 'a') break;
if(pos && s[pos] < s[pos - 1]){
g = 0;
}
}
int ppp = pos;
for(; pos < s.length(); ++pos){
if(s[pos] <= '9' && s[pos] >= '0') break;
if(pos != ppp && pos != s.length() && s[pos] < s[pos - 1]){
g = 0;
}
}
// cout << pos << '\n';
if((!g) || pos != s.length()){
cout << "NO\n";
}
else{
cout << "YES\n";
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
work();
}
B
题意:
给定长度为n的数组a 和 长度为n + 1的数组b, 将a变成b,问至少几步操作
有如下几种操作
- 任意位置+1 或 -1
- 选择任意元素复制到a数组末尾
思路:
对头n位我们需要的操作数是
对于
否则取最接近的
代码:
#include<bits/stdc++.h>
using namespace std;
void work()
{
int n;
cin >> n;
vector<int> a(n + 5);
vector<int> b(n + 5);
for(int i = 1; i <= n; ++i) cin >> a[i];
for(int i = 1; i <= n + 1; ++i) cin >> b[i];
long long ans = 0;
int x = b[n + 1], minn = 0x3f3f3f3f;
for(int i = 1; i <= n; ++i){
ans += abs(a[i] - b[i]);
if(x >= a[i] && x <= b[i] || x >= b[i] && x <= a[i]) minn = 0;
else minn = min(abs(a[i] - x), min(abs(b[i] - x), minn));
}
cout << ans + minn + 1 << '\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
work();
}
C
题意:
给定
贪心操作:我们选取n 个a数组的值,m个b数组的值,对剩余元素按从1到n + m + 1 的序号顺序进行选取,
若n 和 m 都没有选满则根据
思路:
删除操作会影响的只可能有特定的1个数对,即第一个选不到自身max的数对
将每个数对,我们按他们的a, b 较大值进行分组(两组)
对于没选满的一边的数对, 我们可以选其max,
对于选满的一边,按编号头 k 个(k 为本组的最大选取数n or m), 一定可以选其大值,k + 2及之后的数对只能被迫选择 , 唯一会因为删除而改变选择的,只有第k + 1对数
-
删没选满的一边:直接减去删掉的数
-
删选满的一边:
- 删 k + 1 及 之后的数, 直接减去
- 删 头 k 个数, 将第k + 1个的选择取反
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void work()
{
int n, m;
cin >> n >> m;
vector<int> a(n + m + 5), b(n + m + 5);
for(int i = 1; i <= n + m + 1; ++i) cin >> a[i];
for(int i = 1; i <= n + m + 1; ++i) cin >> b[i];
vector<vector<int>> f, s;
vector<int> f_id, s_id;
vector<ll> d(n + m + 5);
ll ans = 0;
for(int i = 1; i <= n + m + 1; ++i){
if(a[i] > b[i]) f.push_back({a[i], b[i]}), f_id.push_back(i);
else s.push_back({a[i], b[i]}), s_id.push_back(i);
}
int g = 1;
if(s.size() > m){
swap(f, s);
swap(f_id, s_id);
swap(n, m);
g = 0;
}
{
for(auto i : s) ans += i[g];
for(int i = 0; i < n; ++i) ans += f[i][g ^ 1];
for(int i = n; i < f.size(); ++i) ans += f[i][g];
for(int i = 0; i < s.size(); ++i)
d[s_id[i]] = ans - s[i][g];
for(int i = n; i < f.size(); ++i)
d[f_id[i]] = ans - f[i][g];
ans += f[n][g^1] - f[n][g];
for(int i = 0; i < n; ++i)
d[f_id[i]] = ans - f[i][g^1];
}
for(int i = 1; i <= n + m + 1; ++i)
cout << d[i] << " ";
cout << '\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
work();
}
D
题意:
能完成括号匹配的括号序列为正常括号序列,问给定正常括号序列的好子串有多少个
好子串 : 将该子串其中的所有括号翻转(左变右,右变左)之后的括号序列依旧是正常序列
思路:
对于括号匹配问题常常可以用前缀和解决问题,左括号+1, 右括号-1, 我们根据前缀和统计答案,
前缀和相等位置之间的左右括号数量相等,但是像是 ()并不能翻转 , 本题多一个翻转后有依旧保证合法的限制,分析一下限制条件
若一个括号序列是好序列则满足:
若一个子串为好子串则满足:
对于每个位置我们可以先把不合法的前缀删掉再进行统计,因为一个前缀在一个位置不合法,则此前缀在之后的位置需要从0重新统计。
代码:
#include<bits/stdc++.h>
using namespace std;
void work()
{
string s;
cin >> s;
map<int, int> cnt;
int b = 0;
long long ans = 0;
cnt[b] = 1;
for(auto& i : s){
b += (i == '(' ? +1 : -1);
// Flase(TLE) :
// for(auto& j : cnt){
// if(j.first * 2 < b) j.second = 0;
// else break;
// }
while((!cnt.empty()) && cnt.begin() -> first * 2 < b)
cnt.erase(cnt.begin());
ans += cnt[b]++;
}
cout << ans << '\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
work();
}
分类:
ACM
标签:
ACM
, Codeforces
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· Apache Tomcat RCE漏洞复现(CVE-2025-24813)