AtCoder Beginner Contest 148 题解

前言

包含题目:

ABC148 A ABC148 B ABC148 C ABC148 D ABC148 E ABC148 F

这次比赛坑好多啊(虽然水了),也可能是我的实现方法不对qaq。

A - Round One

题意

你有三个数:\(1, 2, 3\),现在其中两个数不对,输出对的那个数。

做法

建立一个集合,删去坏的,输出剩下的一个。

用三个if语句判断即可。

程序

考场做法:

#include<bits/stdc++.h>
using namespace std; set<int> t={1,2,3};
int a,b; int main(){ ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0); cin>>a>>b;
t.erase(a);
t.erase(b);
cout<<*t.begin()<<endl; return 0;
}

真实做法:

#include<bits/stdc++.h>
using namespace std; int a,b; int main(){ ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
//三行头文件,可以优化cin、cout速度(但仅能聊以慰籍) cin>>a>>b;
if(a>b)swap(a,b);//swap用作交换两个同一类型的变量的值,此处确保a<b
if(a==1&&b==2)cout<<3;
if(a==1&&b==3)cout<<2;
if(a==2&&b==3)cout<<1; return 0;
}

B - Strings with the Same Length

题意

给你长度\(N\)的字符串\(S\)和\(T\),让你把它们合并起来,方法如下:

拿\(S\)的开头字符,删去,添加到答案串的末尾。拿\(T\)的开头字符,删去,添加到答案串的末尾。

重复以上操作\(N\)次,此时\(S\)和\(T\)应该是空串。

做法

暴力模拟即可,不过不用真的删去字符,从前往后跑就可以了。

程序

#include<bits/stdc++.h>
using namespace std; int n;
string s,t,ans; int main(){ ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0); cin>>n>>s>>t;
for(int i=0;i<n;i++){//从前往后跑s和t的字符
ans+=s[i];
ans+=t[i];//向ans的末尾添加字符
}
cout<<ans<<endl; return 0;
}

C - Snack

题意

给你\(A\)和\(B\),让你求一个数,使得它能被\(A\)和\(B\)整除吗,同时最小(也就是最小公倍数)。

做法

使用辗转相除法先求出最大公因数,对于\(A\)和\(B\),它们的递归的最大公因数求法\(f(A,B)\)如下:

(保证它们都是正整数

  • \(B\)为\(0\),此时返回\(A\)。
  • 返回\(f(B,A\mod B)\)。

\(A \times B \div f(A,B)\)就是最小公倍数。

程序

#include<bits/stdc++.h>
using namespace std; int gcd(int a,int b){//用前文的方法求最大公因数
if(b==0)return a;
else return gcd(b,a%b);
} int main(){ ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0); int a,b;
cin>>a>>b;
cout<<((long long)(a/gcd(a,b)))*b<<endl;//要用long long,不然会爆int return 0;
}

D - Brick Break

题意

给你\(N\)个砖块,每个砖块写有数字\(a_i\),问你删去一些砖块(最多删去\(N-1\)块)后,剩下的\(K\)块砖块,是一个形如\(1,2,3,\dots,K\)的序列时,\(K\)最大是多少,如果不能有这样的序列,那么就输出-1

做法

其实就是求一个形如\(1,2,3,\dots,K\)的\(a_i\)的子序列(子序列的定义是元素可以不连续的),可以\(O(N)\)完成。

不考虑-1,只求出\(K\)最大是多少,那么如果\(K=0\),就输出-1,否则输出\(K\)。

\(K\)的求法:

记录当前的序列的最后一个的值\(c\)(也就是序列的长度)(初始为\(0\)),从前往后跑\(a_i\)中的元素,如果是\(c+1\),那么就把\(c\)加一。这样最后它就是\(K\)了。

程序

#include<bits/stdc++.h>
using namespace std; int n;
int a[200005]; int main(){ ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0); cin>>n;
int c=1;//此处c的值是当前序列的最后一个的值加一,当时写的时候太急,失误了
for(int i=0;i<n;i++){
cin>>a[i];
if(a[i]==c){//如同做法中描述的,是序列长度加一时,就增加序列长度
c++;
}
}
cout<<(n-c+1==n?-1:n-c+1)<<endl;//序列长度为c-1,那么n-c+1就表示删去的东西的个数 return 0;
}

E - Double Factorial

题意

给你一个数\(n\)。

定义一个函数\(f(n)\):

  • \(f(n)=1\) (if \(n<2\))
  • \(f(n)=nf(n−2)\) (if \(n≥2\))

输出函数值的末尾的0的个数。

做法

很容易就可以看出,后缀零的个数只和函数值\(2\)和\(5\)因子的个数有关。

由于\(f(n)\)只要求了\(f(n-2)\),所以奇偶性肯定不会变的,\(n\)为奇数时不可能包含\(2\)作为因数,特判一下。

我们再来看偶数,那么我们可以这么计算\(2\)的因子的个数:

\(i\)从\(1\)开始递增,查看包含\(2^i\)作为因子的数的个数(也就是\(\lfloor { \frac{n}{2^i} } \rfloor\),此处\(\lfloor a \rfloor\)指不超过\(a\)的最大整数,也就是下取整),把函数值中的\(2\)的因子个数加上这个个数,你可能会问了,它包含的因数不应该是\(\lfloor { \frac{n}{2^i} } \rfloor \times i\)吗?其实,里面的\(\lfloor { \frac{n}{2^i} } \rfloor \times ( i - 1 )\),已经在\(\lfloor { \frac{n}{2^{i-1}} } \rfloor\)中加过了,所以就是\(\lfloor { \frac{n}{2^i} } \rfloor\)就可以了。

对于\(5\)的因数,我们可以大致使用同样的方法求,但是每次对于答案的贡献是\(\lfloor { \frac{n}{2 \times 5^i} } \rfloor\),因为必须是偶数,所以需要再乘一个\(2\)以确保只计算了偶数。具体原因如下:

我们举个例子,列出\(1,2,3,\dots,25\)的\(5\)的因子的个数:

\[0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,2
\]

总和是\(6\)。

那么,只计算偶数的话,就只有这样的序列:

\[N,0,N,0,N,0,N,0,N,1,N,0,N,0,N,0,N,0,N,1,N,0,N,0,N
\]

(\(N\)代表奇数,舍去了)总和是\(2\)。

现在可以理解为什么要乘以\(2\)了吧。

程序

#include<bits/stdc++.h>
using namespace std; typedef long long ll; ll n,c2,c5; int main(){ ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0); cin>>n;
if(n&1){
cout<<0<<endl;
return 0;
}
for(ll i=2;i<=n;i*=2){
c2+=n/i;
}
for(ll i=10;i<=n;i*=5){
c5+=n/i;
}
cout<<min(c2,c5)<<endl; return 0;
}

F - Playing Tag on Tree

题意

有一棵\(N\)个结点的树,高桥和青木在上面的\(u\)和\(v\)结点上玩抓人游戏。每个回合如下:

  1. 如果高桥和青木在同一个结点上,游戏结束。高桥选一个和当前结点相邻的结点,走过去。
  2. 如果高桥和青木在同一个结点上,游戏结束。青木选一个和当前结点相邻的结点,走过去。
  3. 开始下一个回合

轮到某人走时,不能停留在同一个结点。

高桥希望回合数尽可能多,青木希望回合数尽可能少,两人都采用最优策略

输出游戏结束时青木走的步数

做法

首先,青木的最优策略很好确定,就是走通向的当前高桥的位置的简单路径就可以了。同时,不论高桥的位置怎样变化,青木走的路径都会沿着通向最终会抓到高桥的结点的这条道路,证明很难,我就不证明了。感性地理解,就是由于高桥和青木不会在途中相遇,所以青木走向的那个(以当前青木所在结点为根的)子树肯定包含高桥和游戏结束时的高桥的终点。

高桥的呢,有点麻烦,所以我们就搜索一下吧qwq(暴力、大好き)。

首先,我们预处理出青木到每个结点的距离,之后搜索高桥的路径(深搜、广搜皆可)。对于当前结点是否可以走,只需要满足高桥到这里的距离严格小于青木到这里的距离即可。特殊地,由于只能移动,不能停留在同一个结点,所以到了叶子结点时,高桥会在相邻结点和这个叶子结点之间重复移动,最终抓到的位置一定是在相邻结点上(一共两种情况,自己手推一下就好了)。

程序

#include<bits/stdc++.h>
using namespace std; int n,ta,ao,ans;
vector<int> g[100005];
int dis[100005]; void dfs(int x,int p,int d){
if(d>=dis[x]){//如果被抓到了就退出
ans=max(ans,dis[x]);
return;
}
for(int i=0;i<g[x].size();i++){
int &y=g[x][i];
if(y!=p){
dfs(y,x,d+1);
}
}
if(g[x].size()==1){//是叶子结点,就特判一下之前做法中提到的情况
ans=max(ans,dis[x]-1);
}
} int main(){ ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0); cin>>n>>ta>>ao;
for(int i=1;i<n;i++){
int a,b;
cin>>a>>b;
g[a].push_back(b);
g[b].push_back(a);
}
memset(dis,-1,sizeof(dis));
dis[ao]=0;
{//预处理青木到每个结点的距离dis
queue<int> q;
q.push(ao);
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0;i<g[x].size();i++){
int &y=g[x][i];
if(dis[y]==-1){
dis[y]=dis[x]+1;
q.push(y);
}
}
}
}
dfs(ta,-1,0);
cout<<ans<<endl; return 0;
}

结束语

感谢观看,感觉自己写得很high,完全没有考虑到别人的观感qaq。所以,有什么意见就评论吧<3<3<3,我一定会改的qaq。

AtCoder Beginner Contest 148 题解的更多相关文章

  1. AtCoder Beginner Contest 154 题解

    人生第一场 AtCoder,纪念一下 话说年后的 AtCoder 比赛怎么这么少啊(大雾 AtCoder Beginner Contest 154 题解 A - Remaining Balls We ...

  2. AtCoder Beginner Contest 153 题解

    目录 AtCoder Beginner Contest 153 题解 A - Serval vs Monster 题意 做法 程序 B - Common Raccoon vs Monster 题意 做 ...

  3. AtCoder Beginner Contest 177 题解

    AtCoder Beginner Contest 177 题解 目录 AtCoder Beginner Contest 177 题解 A - Don't be late B - Substring C ...

  4. AtCoder Beginner Contest 184 题解

    AtCoder Beginner Contest 184 题解 目录 AtCoder Beginner Contest 184 题解 A - Determinant B - Quizzes C - S ...

  5. AtCoder Beginner Contest 173 题解

    AtCoder Beginner Contest 173 题解 目录 AtCoder Beginner Contest 173 题解 A - Payment B - Judge Status Summ ...

  6. AtCoder Beginner Contest 172 题解

    AtCoder Beginner Contest 172 题解 目录 AtCoder Beginner Contest 172 题解 A - Calc B - Minor Change C - Tsu ...

  7. AtCoder Beginner Contest 169 题解

    AtCoder Beginner Contest 169 题解 这场比赛比较简单,证明我没有咕咕咕的时候到了! A - Multiplication 1 没什么好说的,直接读入两个数输出乘积就好了. ...

  8. AtCoder Beginner Contest 151 题解报告

    总的来说,这次的题目比较水,然而菜菜的我并没有把所有题目都做完,话不多说,直接来干货: A:Next Alphabet 题目链接:https://atcoder.jp/contests/abc151/ ...

  9. AtCoder Beginner Contest 115 题解

    题目链接:https://abc115.contest.atcoder.jp/ A Christmas Eve Eve Eve 题目: Time limit : 2sec / Memory limit ...

随机推荐

  1. [bzoj5295]染色

    将这张图化简,不断删掉度为1的点(类似于拓扑排序),构成了一张由环组成的图考虑一个连通块中,设点数为n,边数为m(已经删掉了度为1的点),那么一共只有三种情况:1.一个环($n=m$),一定为YES2 ...

  2. Study Blazor .NET(二)安装

    翻译自:Study Blazor .NET,转载请注明. 安装 请根据下面步骤安装开始使用Blazor: 1.针对不同的操作系统,安装最新版.Net Core框架 [这里] 2.用.Net Core ...

  3. Linux检测磁盘空间

    在linux中,文件系统将所有的磁盘都并入一个虚拟目录下,在使用新的存储媒体之前,需要把它放到虚拟目录下,这项工作称为挂载. 1.mount命令 mount会输出当前系统上挂载的设备列表,要在虚拟目录 ...

  4. Atcoder Regular Contest 125 E - Snack(最小割转化+贪心)

    Preface: 这是生平第一道现场 AC 的 arc E,也生平第一次经历了 performance \(\ge 2800\)​,甚至还生平第一次被 hb 拉到会议里讲题,讲的就是这个题,然鹅比较尬 ...

  5. 关于 KB/KiB、MB/MiB

    ermmm--怎么说呢,这个非常容易搞混,那就写篇 blog 澄清一下吧-- 首先贴上百度百科的官方定义 根据国际单位制标准,1KB = 1000B(字节, Byte). 根据按照 IEC 命名标准 ...

  6. 【Perl】如何安装Bioperl模块?

    目录 失败尝试一:使用cpanm 失败尝试二:使用CPAN 成功尝试:直接conda安装bioperl 没有尝试:源码安装bioperl 生信软件绕不过Perl,Perl绕不过Bioperl.而Bio ...

  7. Admixture的监督分群(Supervised analysis)

    目录 说明 实战 说明 Admixture通过EM算法一般用于指定亚群分类:或者在不知材料群体结构背景下,通过迭代交叉验证获得error值,取最小error对应的K值为推荐亚群数目.如果我们预先已知群 ...

  8. 【7】基于NGS检测体系变异解读和数据库介绍

    目录 解读相关专业术语 体系变异解读规则 体系变异和用药解读流程 主要数据库介绍 解读相关专业术语 2个概念:胚系.体系突变 4种变异类型:SNV.Indel.融合/SV(大的易位/倒位/缺失).CN ...

  9. git添加新账号

    1,在linux上添加账号 useradd test passwd test usermod -G gitgroup  test  将test账号的组改为和git一样的组gitgroup  git所在 ...

  10. “equals”有值 与 “==”存在 “equals”只是比较值是否相同,值传递,==地址传递,null==a,避免引发空指针异常,STRING是一个对象==null,对象不存在,str.equals("")对象存在但是包含字符‘''

    原文链接:http://www.cnblogs.com/lezhou2014/p/3955536.html "equals" 与 "==" "equa ...