比较菜只有 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. Java语言学习day21--7月27日

    ###01接口的概念 * A:接口的概念 接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的"类". 接口只描述所应该具备的方法,并没有具体实现,具体的实现由接口的实 ...

  2. AndroidStudio中的模块依赖引入后用不了

    ------------恢复内容开始------------ 在Android开发中,com.android.tools.build:gradle 3.0 以下版本依赖在gradle 中的声明写法: ...

  3. Vue异步更新机制以及$nextTick原理

    相信很多人会好奇Vue内部的更新机制,或者平时工作中遇到的一些奇怪的问题需要使用$nextTick来解决,今天我们就来聊一聊Vue中的异步更新机制以及$nextTick原理 Vue的异步更新 可能你还 ...

  4. 灵感乍现!造了个与众不同的Dubbo注册中心扩展轮子

    hello大家好呀,我是小楼. 作为一名基础组件开发,服务好每一位业务开发同学是我们的义务(KPI). 客服群里经常有业务开发同学丢来一段代码.一个报错,而我们,当然要微笑服务,耐心解答. 有的问题, ...

  5. 安卓导航抽屉 Navigation Drawer 实现沉浸通知栏

    在使用 Navigation Drawer Activity 模版的时候,遇到了通知栏无法完全沉浸的问题,尝试搜索一些现有的解决方法,但是或多或少都会存在一些问题,通过反复尝试找到找到了一种比较靠谱的 ...

  6. ElasticSearch7.3学习(二十四)----相关度评分机制详解

    1.算法介绍 relevance score(相关性分数) 算法,简单来说,就是计算出,一个索引中的文本,与搜索文本,他们之间的关联匹配程度.Elasticsearch使用的是 term freque ...

  7. supervisor安装以及监控管理rabbitmq消费者进程

    简介:Supervisor是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启. 1.安装 apt-get install ...

  8. mysqldump还原备份数据时遇到一个问题

    问题描述 ERROR 1839 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_MODE = O ...

  9. 使用 oh-my-posh 美化 windows terminal,让其接近oh-my-zsh

    本文旨在快速让你进行美化,少踩一些坑,原文出自我的博客:prettier-windows-terminal-with-oh-my-posh 为了同 iterm2 下的 oh-my-zsh 保持基本一致 ...

  10. MySQL 事务常见面试题总结 | JavaGuide 审核中

    <Java 面试指北>来啦!这是一份教你如何更高效地准备面试的小册,涵盖常见八股文(系统设计.常见框架.分布式.高并发 ......).优质面经等内容. 本文原发于 MySQL知识点&am ...