比较菜只有 A ~ E

A.Erasing Zeroes

题目描述:

原题面

题目分析:

使得所有的 \(1\) 连续也就是所有的 \(1\) 中间的 \(0\) 全部去掉,也就是可以理解为第一个 \(1\) 到最后一个 \(1\) 中间的 \(0\) 全部去掉,也就是它们之间 \(0\) 的个数,那么就顺序、逆序扫一遍就出来了。

代码详解:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
string s;
cin>>s;
int l = -1,r = -1;
for(int i=0; i<s.size(); i++){
if(s[i] == '1'){
l = i;
break;
}
}
for(int i=s.size(); i>=0; i--){
if(s[i] == '1'){
r = i;
break;
}
}
if(l == -1){
printf("0\n");
continue;
}
int ans = 0;
for(int i=l; i<=r; i++){
if(s[i] == '0'){
ans++;
}
}
printf("%d\n",ans);
}
return 0;
}

B.National Project

题目描述:

原题面

题目分析:

题目要求是至少有一半是在好天气中修的,那么我们就考虑如果好天气都修那么修到哪一天可以满足这个条件。

我们可以将每 \(g\) 天视为一轮,那么总共就有 \(\lfloor\dfrac{\lceil \dfrac{n}{2} \rceil}{g}\rfloor\) 个完整的轮数,以及多出来的 \(\lceil \dfrac{n}{2} \rceil\% g\) 天。这一轮既有好天气也有坏天气,所以最后得到在哪一天可以满足条件时要算上坏天气的天数。如果多出来的天数不为 \(0\),那么就意味着这么多轮坏天气都需要经过,而如果多出来的天数为 \(0\),那么意味着经过坏天气的轮数是我们求出来的轮数减一,因为最后一轮不需要经过坏天气。

所以最后在哪一天可以满足条件的答案就是:(令 \(x = \lfloor\dfrac{\lceil \dfrac{n}{2} \rceil}{g}\rfloor\))

(1)若有多余的天数:\(x \times (g+b) + \lceil \dfrac{n}{2} \rceil\% g\)

(2)若没有多余的天数:\((x-1)\times b + x \times g\)

需要注意的是这几天只是满足好天气一半的条件,不一定可以全部修完,所以需要与 \(n\) 取 \(\max\)

代码详解:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int main(){
long long t;
cin>>t;
while(t--){
long long n,g,b;
cin>>n>>g>>b;
long long x = (n+1)/2/g;
if(((n+1)/2)%g == 0){
printf("%lld\n",max((x-1) * b + x * g,n));
}
else{
printf("%lld\n",max(x * (g+b) + ((n+1)/2) % g,n));
}
}
return 0;
}

一个优美的技巧:\(\lceil \dfrac{n}{2} \rceil\) 可以写为: \(\lfloor \dfrac{n+1}{2} \rfloor\)

C.Perfect Keyboard

题目描述:

原题面

题目分析:

这种题很显然要先考虑转化为图上的问题。

很显然我们可以在 \(S\) 中相邻的两个字符之间连边,表示这两个字符必须相邻。

判断无解的条件也很明显了:

(1)某个点的度数大于等于 \(3\),因为一条连边表示一个相邻关系,不可能同时与三个字符相邻。

(2)出现大于等于 \(3\) 的环,这个也是相当显然的自己手推一下就知道不可能

那么剩下的就是一条条的链了,那么就按顺序扫过这一条链,到了某个节点就输出这个节点代表的字母就好了,为了避免重复输出应该记一个数组表示这个字母有没有输出过。也需要注意一点:要从度数为 \(1\) 的点开始扫,因为度数为 \(2\) 意味着一种中间的关系,显然只能一边边地输出无法从中间扩展。

代码详解:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 50;
int head[MAXN],cnt,du[MAXN],edge[MAXN][MAXN];
bool vis[MAXN],flag,use[MAXN];
void dfs(int now,int from){
vis[now] = true;
for(int i=0; i<26; i++){
if(i == from || !edge[now][i] || now == i) continue;
if(vis[i]){
flag = true;
return;
}
dfs(i,now);
}
}
void get_ans(int now,int from){
if(!vis[now])
cout<<char(now + 'a');
vis[now] = true;
for(int i=0; i<26; i++){
if(vis[i] || i == from || !edge[now][i] || now == i) continue;
get_ans(i,now);
}
}
int main(){
int t;
cin>>t;
while(t--){
memset(edge,0,sizeof(edge));
memset(vis,false,sizeof(vis));
memset(use,false,sizeof(use));
memset(du,0,sizeof(du));
cnt = 0;
flag = false;
int mx = 0;
string s;
cin>>s;
for(int i=0; i<s.size() - 1; i++){
if(!edge[s[i]-'a'][s[i+1]-'a']){
du[s[i]-'a']++;
du[s[i+1]-'a']++;
mx = max(mx,max(du[s[i]-'a'],du[s[i+1]-'a']));
}
edge[s[i]-'a'][s[i+1]-'a'] = true;
edge[s[i+1]-'a'][s[i]-'a'] = true;
use[s[i] - 'a'] = true;
use[s[i+1] - 'a'] = true;
}
for(int i=0; i<26; i++){
if(!vis[i]){
dfs(i,i);
}
if(flag)
break;
}
if(flag || mx >= 3){
printf("NO\n");
}
else{
printf("YES\n");
memset(vis,false,sizeof(vis));
for(int i=0; i<26; i++){
if(du[i] == 1)
get_ans(i,i);
}
for(int i=0; i<26; i++){
if(!vis[i])
cout<<char(i + 'a');
}
printf("\n");
}
}
return 0;
}

因为可能含有大量的重边而且点的数量很少所以可以考虑使用邻接矩阵。

输出的时候也要注意可能有的点没有出现那么就在最后输出这些没有出现的点。

所谓有大小大于等于三的环也可以理解为无向图上的有环,也就是如果从当前节点可以到达一个曾经访问过但不是其父亲的点那么就意味着有环。

D.Fill The Bag

题目描述:

原题面

题目分析:

考虑物品大小都是 \(2\) 的非负整数次幂也就可以联想到将 \(n\) 二进制拆分,因为这些物品的顺序不影响答案所以就考虑将他们存放到 \(cnt\) 数组中去。

考虑如果 \(n\) 的当前位我们数组中有那么直接减就好了,很显然这样做最优。而如果没有那么就要考虑是用比当前位小的那些数加和凑出这个位还是从比当前位更大的位拆。

那么这样就意味着我们要维护一个 \(sum\) 代表比当前位小的那些数的和,如果这个值大于当前位的值显然就扫一遍比它小的位然后减去这些位的值直到减为 \(0\) 就好。

而如果用比它小的数凑不出来当前位那么就找到比当前位大的最小的有值一位,然后从这一位一直拆,拆到当前位然后减掉就好了。

代码详解:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const long long MAXN = 3e5+5;
long long cnt[MAXN];
int main(){
long long t;
cin>>t;
while(t--){
memset(cnt,0,sizeof(cnt));
long long flag = 0;
long long n,m;
long long mx = 0;
cin>>n>>m;
for(long long i=1; i<=m; i++){
long long a;
cin>>a;
cnt[int(log2(a))]++;
mx = max(mx,a);
flag += a;
}
if(flag < n){
printf("-1\n");
continue;
}
long long sum = 0;
long long now = 0;
long long ans = 0;
while(n){
if(n & 1){
if(cnt[now]){
cnt[now]--;
}
else if(sum >= (1<<now)){ //用低位补
long long res = (1<<now);
for(long long i=now-1; i>=0 && res; i--){
if(cnt[i] * (1<<i) <= res){
sum -= cnt[i] * (1<<i);
res -= cnt[i] * (1<<i);
cnt[i] = 0;
}
else{
while(cnt[i] && (1<<i) <= res){
res -= (1<<i);
sum -= (1<<i);
cnt[i]--;
}
}
}
}
else{ //找到高位拆
for(long long j = now+1; j<=mx; j++){
if(cnt[j]){
for(long long k=j; k>now; k--){
cnt[k-1] += 2;
cnt[k]--;
ans++;
}
break;
}
}
cnt[now]--;
}
}
n>>=1;
sum += cnt[now] * (1<<now);
now++;
}
cout<<ans<<endl;
}
return 0;
}

注意一开始先判断有无解,也就是所有数加起来能不能大于等于 \(n\),若能大于等于显然有解。

E.Erase Subsequences

题目描述:

原题面

题目分析:

我们很明显可以想出来一步:枚举 \(t\) 在哪里拆开,然后将 \(t\) 转化为 \(t1+t2\),再判断 \(s\) 中能不能拆出 \(t1,t2\) 就好了。

那么问题就转化为了 \(s\) 中能不能拆出来的问题了。发现可能需要 \(dp\) 求解。

很显然的状态是:\(dp[i][j][k]\) 表示 \(s\) 的前 \(i\) 位能不能拆出 \(t1\) 的前 \(j\) 位和 \(t2\) 的前 \(k\) 位,因为状态量过大我们就考虑优化这个状态。

也就是将状态改写为:\(dp[i][j]\) 表示 \(s\) 的前 \(i\) 位拆出 \(t1\) 的前 \(j\) 位最多再拆出 \(t2\) 的前多少位。这样当 \(dp[size_s][size_{t1}] = size_{t2}\) 时也就意味着可以拆出。

那么就考虑转移,转移也就是做决策,这里的决策显然就是 \(s\) 的当前位应该放到 \(t1\) 的后面还是 \(t2\) 的后面还是都不放,这样也能保证是不相交的子序列。

(1)当 \(s[i+1] = t1[j+1]\) 时,\(dp[i][j] -> dp[i+1][j+1]\)

(2)当 \(s[i+1] = t2[f[i][j] + 1]\) 时,\(dp[i][j] + 1 -> dp[i+1][j]\)

(3)任何情况下,\(dp[i][j] -> dp[i+1][j]\),这个也十分显然

代码详解:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 805;
int f[MAXN][MAXN];
bool check(string s,string t1,string t2){
memset(f,-1,sizeof(f));
f[0][0] = 0;
s = '0' + s;
t1 = '0' + t1;
t2 = '0' + t2;
for(int i=0; i<s.size(); i++){
for(int j=0; j<t1.size(); j++){
if(f[i][j] == -1) continue;
f[i+1][j] = max(f[i+1][j],f[i][j]);
if(s[i+1] == t1[j+1]) f[i+1][j+1] = max(f[i+1][j+1],f[i][j]);
if(s[i+1] == t2[f[i][j] + 1]) f[i+1][j] = max(f[i+1][j],f[i][j] + 1);
}
}
if(f[s.size()-1][t1.size()-1] == t2.size()-1)
return true;
return false;
}
bool solve(string s,string t){
for(int i=0; i<=t.size(); i++){
string t1,t2;
for(int j=0; j<i; j++){
t1 = t1 + t[j];
}
for(int j=i; j<t.size(); j++){
t2 = t2 + t[j];
}
if(check(s,t1,t2))
return true;
}
return false;
}
int main(){
int n;
cin>>n;
while(n--){
string s,t;
cin>>s>>t;
if(solve(s,t)){
printf("YES\n");
}
else{
printf("NO\n");
}
}
return 0;
}

我们会发现对于 \(dp\) 的边界、初值不好设置,那么就将所有的字符串前面加上一位那就好转移了。

【题解】Educational Codeforces Round 82的更多相关文章

  1. Educational Codeforces Round 82 (Rated for Div. 2) A-E代码(暂无记录题解)

    A. Erasing Zeroes (模拟) #include<bits/stdc++.h> using namespace std; typedef long long ll; ; in ...

  2. Educational Codeforces Round 82 (Rated for Div. 2)

    题外话 开始没看懂D题意跳了,发现F题难写又跳回来了.. 语文好差,码力好差 A 判第一个\(1\)跟最后一个\(1\)中\(0\)的个数即可 B 乘乘除除就完事了 C 用并查集判一下联通,每个联通块 ...

  3. Educational Codeforces Round 82 (Rated for Div. 2)E(DP,序列自动机)

    #define HAVE_STRUCT_TIMESPEC #include<bits/stdc++.h> using namespace std; ],t[]; int n,m; ][]; ...

  4. Educational Codeforces Round 82 (Rated for Div. 2)D(模拟)

    从低位到高位枚举,当前位没有就去高位找到有的将其一步步拆分,当前位多余的合并到更高一位 #define HAVE_STRUCT_TIMESPEC #include<bits/stdc++.h&g ...

  5. Educational Codeforces Round 82 C. Perfect Keyboard

    Polycarp wants to assemble his own keyboard. Layouts with multiple rows are too complicated for him ...

  6. Educational Codeforces Round 82 B. National Project

    Your company was appointed to lay new asphalt on the highway of length nn. You know that every day y ...

  7. Educational Codeforces Round 82 A. Erasing Zeroes

    You are given a string ss. Each character is either 0 or 1. You want all 1's in the string to form a ...

  8. [CF百场计划]#3 Educational Codeforces Round 82 (Rated for Div. 2)

    A. Erasing Zeroes Description You are given a string \(s\). Each character is either 0 or 1. You wan ...

  9. Educational Codeforces Round 63 (Rated for Div. 2) 题解

    Educational Codeforces Round 63 (Rated for Div. 2)题解 题目链接 A. Reverse a Substring 给出一个字符串,现在可以对这个字符串进 ...

随机推荐

  1. CentOS8 AnolisOS8 yum安装 No match for argument: htop Error: Unable to find a match: htop

    这里写自定义目录标题 CentOS8 AnolisOS8 yum安装失败 安装失败原因 阿里云官方镜像主页 正确的操作步骤 学习交流 My Blog 技术交流 CentOS8 AnolisOS8 yu ...

  2. mysql常见的5种日志

    点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人. 文章不定期同步公众号,还有各种一线大厂面试原题.我的学习系列笔记. 错误日志(errorlog) 用来记录mysqlId的错误信息,如数据库 ...

  3. mask-image实现聚光灯效果

    大家好,我是半夏,一个刚刚开始写文的沙雕程序员.如果喜欢我的文章,可以关注 点赞 加我微信:frontendpicker,一起学习交流前端,成为更优秀的工程师-关注公众号:搞前端的半夏,了解更多前端知 ...

  4. Error:java: Can‘t generate mapping method with primitive return type.报错

    原因:Spring项目中使用了JPA以及Mybatis–mapper文件注解引错包导致编译错误 解决: 错误:import org.mapstruct.Mapper;正确路径:import org.a ...

  5. OAuth 2.1 框架

    OAuth 2.1 Draft 当前版本:v2-1-05 失效时间:2022/09/08 本文对部分原文翻译,同时加了一些笔记,以便理解. 单词 译意 identifiler 识别码 Resource ...

  6. Kubernetes生产环境最佳实践

    点击上方"开源Linux",选择"设为星标" 回复"学习"获取独家整理的学习资料! 众所周知,Kubernetes很难! 以下是在生产中使用 ...

  7. 用漫画了解Linux内核到底长啥样

    一个执着于技术的公众号 原文链接:http://985.so/hRL6 往期精彩 ◆  干货 | 给小白的Nginx10分钟入门指南 ◆  什么是集群?看完这篇你就知道啦! ◆  干货 | Linux ...

  8. typeScript类型总结

    1.对象类型 {} 用来指定对象中可以包含哪些属性,在属性名后加?表示属性是可选的 语法:{属性名:属性值类型,属性名:属性值类型} 示例: let a:{name:string,age?:numbe ...

  9. 运维:DevSecOps

    什么是DevSecOps DevSecOps 是一场关于 DevOps 概念实践或艺术形式的变革.DevOps之父Patrick Debios 强调:"DevOps2.0时代应首先解决人的问 ...

  10. 122_Power Pivot&Power BI不连续日期的日环比

    博客:www.jiaopengzi.com 焦棚子的文章目录 请点击下载附件 一.背景 这两天有朋友在交流,dax中使用时间智能函数写日环比,一个 dateadd 就可以了.但是有些业务不是每天都连续 ...