比较菜只有 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语言学习day38--8月13日

    ###11哈希表的数据结构 A:哈希表的数据结构:(参见图解) 加载因子:表中填入的记录数/哈希表的长度 例如: 加载因子是0.75 代表: 数组中的16个位置,其中存入16*0.75=12个元素 如 ...

  2. Android 12(S) 图像显示系统 - 基础知识之 BitTube

    必读: Android 12(S) 图像显示系统 - 开篇 一.基本概念 在Android显示子系统中,我们会看到有使用BitTube来进行跨进程数据传递.BitTube的实现很简洁,就是一对&quo ...

  3. Django安装+创建一个Django项目

    安装 选用pycharm    在终端输入命令:pip install django 安装完成后创建项目 1.在你想创建项目的目录下输入下面的代码 2.django-admin startprojec ...

  4. Django与socket

    Web框架本质是socket 各种socket一般都遵循wsgi协议 Django里面没有socket Django映射到Web框架,用了一个别人的socket:wsgiref 所以:django默认 ...

  5. 一篇讲清楚String、StringBuffer和StringBuild

    ​ ​ 一.String篇 1.String基本介绍? (jdk文档原文)String类代表字符串. Java程序中的所有字符串文字(例如"abc" )都被实现为此类的实例. 说人 ...

  6. 2003031121-浦娟-python数据分析第三周作业-第一次作业

    项目 内容 课程班级博客链接 https://edu.cnblogs.com/campus/pexy/20sj 作业链接 https://edu.cnblogs.com/campus/pexy/20s ...

  7. Redisson报错

    org.redisson.client.RedisResponseTimeoutException: Redis server response timeout (3000 ms) occured a ...

  8. 我怀疑这是IDEA的BUG,但是我翻遍全网没找到证据!

    你好呀,我是歪歪. 前几天有朋友给我发来这样的一个截图: 他说他不理解,为什么这样不报错. 我说我也不理解,把一个 boolean 类型赋值给 int 类型,怎么会不报错呢,并接着追问他:这个代码截图 ...

  9. vc2010以及VS2019安装使用教程

    一.vc2010的安装教程. ①下载(由于是一个离线文件,可关注后找我) ②下载好并解压安装文件后,打开解压后的文件进行运行安装. 点击"setup"根据提示安装即可. ③安装后点 ...

  10. 类型安全的 Go HTTP 请求

    前言 对 Gopher 来说,虽然我们基本都是在写代码让别人来请求,但是有时候,我们也需要去请求第三方提供的 RESTful 接口,这个时候,我们才能感受到前端同学拼接 HTTP 请求参数的痛苦. 比 ...