Educational Codeforces Round 168 (Rated for Div. 2) 题解
本文网址:https://www.cnblogs.com/zsc985246/p/18333684 ,转载请注明出处。
D 题不知道为什么挂了一发。最终排名 135,Div2 选手排名 64。
F 题解请等待后续更新。
传送门
Educational Codeforces Round 168 (Rated for Div. 2)
A.Strong Password
题目大意
给定一个字符串 ,你需要在中间(可以是开头或结尾)插入一个字符,使得满足 的 最多。
多组测试,。
思路
如果有两个字符相邻且相同,直接在这它们之间插入一个不同于它们的字符。否则在字符串结尾插入一个不同于结尾的字符。
代码实现
#include<bits/stdc++.h>
#define ll long long
#define For(i,a,b) for(ll i=(a);i<=(b);++i)
#define Rep(i,a,b) for(ll i=(a);i>=(b);--i)
#define pb push_back
const ll N=1e6+10;
using namespace std;
ll n,m,k;
char a[N],b[N];
void mian(){
scanf("%s",a+1);
n=strlen(a+1);
ll flag=0;
For(i,1,n-1){
putchar(a[i]);
if(a[i]==a[i+1]&&flag==0){
if(a[i]=='a')putchar('b');
else putchar('a');
flag=1;
}
}
putchar(a[n]);
if(flag==0){
if(a[n]=='a')putchar('b');
else putchar('a');
}
putchar('\n');
}
int main(){
int T=1;
scanf("%d",&T);
while(T--)mian();
return 0;
}
B.Make Three Regions
题目大意
有一个 的网格,上面有些格子是障碍物,有些是空地。保证空地四连通。
求有多少个空地满足把它变成障碍物后,剩余的空地被分为三个四连通块。
多组测试,。
思路
发现只有如下两种情况:
x.x ...
... x.x
特判即可。
代码实现
#include<bits/stdc++.h>
#define ll long long
#define For(i,a,b) for(ll i=(a);i<=(b);++i)
#define Rep(i,a,b) for(ll i=(a);i>=(b);--i)
#define pb push_back
const ll N=1e6+10;
using namespace std;
ll n,m,k;
char a[N],b[N];
void mian(){
ll ans=0;
scanf("%lld",&n);
scanf("%s",a+1);
scanf("%s",b+1);
For(i,1,n-2){
if(a[i]=='x'&&a[i+1]=='.'&&a[i+2]=='x'&&b[i]=='.'&&b[i+2]=='.'){
++ans;
}
if(b[i]=='x'&&b[i+1]=='.'&&b[i+2]=='x'&&a[i]=='.'&&a[i+2]=='.'){
++ans;
}
}
printf("%lld\n",ans);
}
int main(){
int T=1;
scanf("%d",&T);
while(T--)mian();
return 0;
}
C.Even Positions
题目大意
一个合法括号序列的权值定义为匹配括号的距离和。
有一个长度为 的合法括号序列,但所有的奇数位置的括号都遗失了。你需要找出所有可能的原序列中,权值最小的为多少。
多组测试, 为偶数,。
思路
发现对于一个右括号,我们会尽可能在它前面放左括号,而对于一个左括号,我们会在它后面放右括号。
手玩发现,为了使括号序列合法,我们会先满足左括号,再考虑右括号。
也就是说,一个左括号出现时,它后面最近的右括号的匹配括号会左移 ,最后权值也会增加 。
统计左括号的数量 , 即为答案。
代码实现
#include<bits/stdc++.h>
#define ll long long
#define For(i,a,b) for(ll i=(a);i<=(b);++i)
#define Rep(i,a,b) for(ll i=(a);i>=(b);--i)
#define pb push_back
const ll N=1e6+10;
using namespace std;
ll n,m,k;
char a[N],b[N];
void mian(){
ll ans=0;
scanf("%lld",&n);
scanf("%s",a+1);
ans=n/2;
For(i,1,n){
if(a[i]=='('){
ans+=2;
}
}
printf("%lld\n",ans);
}
int main(){
int T=1;
scanf("%d",&T);
while(T--)mian();
return 0;
}
D.Maximize the Root
题目大意
给定一棵 个点的树,根为 。第 个点有一个权值 。
你可以多次操作:选择一个点,让其子树所有点(不包括自己)权值减 ,自己权值加 。
权值不能为负。求最后根节点的最大权值。
多组测试, 为偶数,。
思路
明显不能贪心。考虑 dp。
我们要让根节点尽可能大,那么就要让根节点能进行的操作数尽可能多。
而操作数取决于子树中权值最小的点的权值。
令 表示 的子树操作完之后最小值的最大值。
转移时,令 为 的儿子节点的 值的最小值,分类讨论:
-
。此时操作只会让最小值更小。。
-
。此时我们可以操作直到 ,这样最小值会变大。。
注意我们是要让根节点权值最大,所以在根节点上不需要考虑子树最小值最大,直接无脑操作即可。
代码实现
根节点记得特判。
#include<bits/stdc++.h>
#define ll long long
#define For(i,a,b) for(ll i=(a);i<=(b);++i)
#define Rep(i,a,b) for(ll i=(a);i>=(b);--i)
#define pb push_back
const ll N=1e6+10;
using namespace std;
ll n,m,k;
ll a[N],b[N];
ll fa[N];
vector<ll>e[N];
void dfs(ll x){
ll mn=1000000001;
for(ll y:e[x]){
if(y==fa[x])continue;
dfs(y);
mn=min(mn,b[y]);
}
if(mn==1000000001){
b[x]=a[x];
return;
}
if(x==1){
a[x]+=mn;
return;
}
if(a[x]<mn)b[x]=(a[x]+mn)/2;
else b[x]=mn;
}
void mian(){
ll ans=0;
scanf("%lld",&n);
For(i,1,n){
scanf("%lld",&a[i]);
e[i].clear();
b[i]=0;
}
For(i,2,n){
scanf("%lld",&fa[i]);
e[i].pb(fa[i]),e[fa[i]].pb(i);
}
dfs(1);
printf("%lld\n",a[1]);
}
int main(){
int T=1;
scanf("%d",&T);
while(T--)mian();
return 0;
}
E.
题目大意
有一个长度为 的序列 和整数 , 一开始等于 。
一次操作定义为:依次对 ,每 次满足 ,。
现在告诉你序列 ,有 次询问,每次询问给定 ,求在 、操作进行到 时, 是否满足。
。
思路
没有修改操作,首先想到预处理。
手玩发现,对于每个 ,满足条件的 是一个范围,即大于等于一个阈值 。
所以我们需要做的,就是快速求出每个 的阈值。
如果求单个 的阈值,我们可以使用二分答案。这样做的复杂度瓶颈在 check 函数上。
那么为了降低复杂度,我们需要寻找共用的信息。
我们发现,check 的本质其实是在找之前有多少下标已经满足条件。
那么我们直接开一颗权值线段树,记录当前的每个 值对应的满足条件的下标数。
每次计算出一个 ,将线段树上 整体加 。查询时单点查询。
二分答案套上一个线段树,复杂度 。
代码实现
#include<bits/stdc++.h>
#define ll long long
#define For(i,a,b) for(ll i=(a);i<=(b);++i)
#define Rep(i,a,b) for(ll i=(a);i>=(b);--i)
#define Yes printf("Yes\n")
#define No printf("No\n")
#define pb push_back
const ll N=1e6+10;
using namespace std;
ll n,m,k,q;
ll a[N],b[N];
#define lson rt<<1
#define rson rt<<1|1
ll c[N];
void build(ll rt,ll l,ll r){
if(l==r){
c[rt]=0;
return;
}
ll mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
}
void pushdown(ll rt,ll l,ll r){
ll mid=(l+r)>>1;
if(c[rt]){
c[lson]+=c[rt];
c[rson]+=c[rt];
c[rt]=0;
}
}
void change(ll rt,ll l,ll r,ll x,ll y,ll z){
if(x<=l&&r<=y){
c[rt]+=z;
return;
}
pushdown(rt,l,r);
ll mid=(l+r)>>1;
if(x<=mid)change(lson,l,mid,x,y,z);
if(y>mid)change(rson,mid+1,r,x,y,z);
}
ll query(ll rt,ll l,ll r,ll x){
if(l==r)return c[rt];
pushdown(rt,l,r);
ll mid=(l+r)>>1;
if(x<=mid)return query(lson,l,mid,x);
else return query(rson,mid+1,r,x);
}
void mian(){
ll ans=0;
scanf("%lld%lld",&n,&q);
For(i,1,n){
scanf("%lld",&a[i]);
b[i]=0;
}
build(1,1,n);
change(1,1,n,1,n,1);
For(i,2,n){
ll l=1,r=n,res=0;
while(l<=r){
ll mid=(l+r)>>1;
if(query(1,1,n,mid)/mid+1>a[i])l=mid+1;
else res=mid,r=mid-1;
}
b[i]=res;
change(1,1,n,res,n,1);
}
while(q--){
ll x,y;
scanf("%lld%lld",&x,&y);
if(b[x]<=y)Yes;
else No;
}
}
int main(){
int T=1;
while(T--)mian();
return 0;
}
F.
题目大意
思路
代码实现
尾声
如果有什么问题,可以直接评论!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!