【HelloCodeCPP】入门思维题 & 题解
声明
题解由 \(hzj\) 编写
前言
为了零食大礼包,我毫不犹豫地报名了 【Contest1243 - 入门思维题】
。
写题解之前,我得先证明我的 \(\colorbox{lightgreen}{AK}\) 记录:
比赛详情与头图
接下来我来细细地讲解一下关于这场比赛的信息: 首先时间是 3月25日至3月31日 ,错过了还能再做,但零食大礼包会被 \(admin\) 收走。并且此次比赛并没有按照难度排序,我猜测难度大概在 \(\colorbox{red}{入门} \sim \colorbox{orange}{普及-}\) 。总的来说,D题是最难的一道题目。
【Question A】 杯子
题目跳转 : 问题 A: 杯子
题解
\(admin\) 已经把这道题的两种情况的样例给了出来,我们把这两个样例分析到位,也就是正解了。
为了方便讲解,我将此题的水的体积单位为 \(Vm\)
分析【样例一】
现在有 \(2\) 个杯子,每个杯子有 \(2Vm\) 水,每个杯子的容积为 \(5Vm\) 。
要让一个杯子里的水最多,我们会优先考虑将所有的水 浇给 到一个杯子里。但前提是那个杯子得容得下,即 \(a \ge b \times n\)。
样例一的代码就出来了
……
if (a >= b*n)
{
cout<<b*n;
}
……
分析【样例二】
因为倒水不能溢出,所以我们直接从每个杯子的容量中减去那些多出来的水,即 \(a - (a \mod b)\)
样例二的代码也就出来了
……
(样例一的代码)
else
{
cout<<(a-(a%b));
}
……
70pts 答案
缝合一下刚才的代码,(半)正解就出来了。
#include <cstdio>
#include <iostream>
using namespace std;
int a,b,n;
int main()
{
cin>>a>>b>>n;
if (b*n<=a)
cout<<n*b;
else
cout<<(a-(a%b));
return 0;
}
最后的分析 & AC代码
注意一下数据:
我们在一开始要求 \(b \times n\) , 我们用数据给的最大值来算,即 \(10^9 \times 10^9\) ,算出来结果可是 \(10 ^{18}\),而 int
的数据范围只有 \(\le 10 ^{10}\) ,所以我们要开 long long
:
#include <cstdio>
#include <iostream>
using namespace std;
long long int a,b,n;
int main()
{
cin>>a>>b>>n;
if (b*n<=a)
cout<<n*b;
else
cout<<(a-(a%b));
return 0;
}
【Question B】 隐藏自身
题目跳转 : 问题 B: 隐藏自身
题解
题目简单翻译一下:要求让第一个数减第二个数之差变得最小,接着在整个数组内找最大的的差值。
我怎么一说,这道题目就很简单了。
【分析】 排序
我们要让 \(A_i - A_{i+1}\) 的值最小,我们会让 \(A_i\) 尽可能的小于 \(A_{i-1}\) 。当然,这个数组可以任意变换顺序,所以我们会直接想到 排序 。
我直接写上最常见的三种排序:
// 第一种——冒泡排序
#include <cmath>
……
for (int i=1;i<=n-1;i++)
{
for (int j=1;j<=n-1;j++)
{
if (arr[j]<arr[i])
swap(arr[i],arr[j]);
}
}
// 第二种——选择排序(稳定版)
#include <cmath>
……
for (int i=1;i<=n-1;i++)
{
for (int j=i+1;j<=n;j++)
{
if (arr[j]<arr[i])
swap(arr[i],arr[j]);
}
}
//第三种——sort排序
#include <algorithm>
……
sort(arr+1,arr+1+n);//sort排序 默认从小到大排序
【分析】 找最大差值
找最大差值,普遍的方法是暴力枚举(打擂台),刚好本题的时间复杂度也是允许暴力的:
#include <cmath>
……
const int INT=1e7+1;
int _max=-INT;
for (int i=1;i<=n-1;i++)
{
_max=max(arr[i]-arr[j],_max);
}
AC答案
我们结合刚才的 排序 与 找最大差值,很快就能写出 \(\colorbox{lightgreen}{AC}\) 的答案。
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int R=1e7;
int n,arr[R],ans=-R;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&arr[i]);
sort(arr+1,arr+1+n);
for (int i=1;i<=n-1;i++)
ans=max(ans,arr[i]-arr[i+1]);
printf("%d",ans);
}
【Question C】 感应门
题目链接 :问题 C: 感应门
由于我经常由于不开 \(\texttt{long long }\) ,扣了好多分,于是做这类题,我就习惯开 \(\texttt{long long}\)了。
题解
不废话,我们直入主题:这感应门其实就两种情况。
【分析】 第一种情况
如果当前的时间点刚好门还开着
我们先记录答案,即 \(Ans=Ans+(冷却时间)d-Ton(当前门的开放时间)+Arr_i(当前这个人进门的时间点)\)
接着就要在门开放的时间加上那个人过去后的冷却时间,即 \(Ton=Ton+d-Ton+Arr_i\)。
【分析】 第二种情况
如果当前时间点门未开
很简单,答案记录 \(Ans+d\) , 门的开放时间加上冷却时间,即 \(Ton+=d\)。
AC代码
我们把中心代码列出来的,所有代码也就出来了:
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
long long arr[100001];
long long n,d,ton,ans;
int main()
{
cin>>n>>d;
for (int i=1;i<=n;i++)
cin>>arr[i]
for (int i=1;i<=n;i++)
{
if (arr[i]<=ton)
{
ans+=d-ton+arr[i];
ton=ton+d-ton+arr[i];
}
else
{
ans+=d;
ton=arr[i]+d;
}
}
cout<<ans;
}
【Question D】 增长与翻倍
题目链接 : 问题 D: 增长与翻倍
老样子,开 \(\texttt{long long}\) 。这道题有点难,我们要换一种思维方式。
题解
这道题目的解释就是在 迷惑 我们,谁说一定要让 \(s\) 变成 \(t\) ,我一身反骨,我要让 \(t\) 变成 \(s\) !
【分析】 如何倒推
我们 打表列举 或 观察样例 就会发现,当 \(t\) 是 \(2\) 的倍数时,它会优先考虑 \(\div 2\)。
但也不能随意地 \(\div\) 2,他得看能不能 \(\div 2\) ,也就是 \(t \div 2 \ge s\) 。
如果不能 \(\div 2\) ,那就 \(-1\),代码也就出来了
AC代码
#include<bits/stdc++.h>
using namespace std;
int s,t,step;
int main()
{
cin>>s>>t;
while (s!=t)
{
if (t%2==0 and t/2>=s) t/=2;
else t--;
step++;
}
cout<<step;
return 0;
}
【Question E】 字符串的处理
题目链接 : 问题 E: 字符串的处理
题外话
虽然这道题相当的简单,但是 \(hzj\) 提交了 \(22\) 次才 \(\colorbox{lightgreen}{AC}\) ,提交记录。
题解
这道题首先大家会想到 模拟 ,用双循环来解决,但时间复杂度为 \(O(q^2)\) , 而 \(q\) 的数据范围为 \(10^5\) ,明显会超时。
我们先达标列举一下
S=011
STEP: 1 2 3 4 ……
翻转: 110 001 110 001 ……
反转: 100 001 100 001 ……
我们会发现,当 次数 是奇数时,相当于没变,所以我们总结出: \(当 Step\%2==1\) 时,才进行操作
我们就可以记录一下操作的次数,看是不是奇数
for (long long i=0;i<q;i++)
{
if (w[i]=='1')
cnt_1++;
else
cnt_2++;
}
翻转与反转十分简单,一个判断,一个头尾指针,详细代码如下:
long long len=s.size()-1;
if (cnt_1%2==1)
{
int l=0,r=len;
while (l<r)
{
char tmp=s[l];
s[l]=s[r];
s[r]=tmp;
l++;
r--;
}
}
if (cnt_2%2==1)
{
for (long long i=0;i<=len;i++)
{
if (s[i]=='1')
s[i]='0';
else
s[i]='1';
}
}
AC 代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
long long q,cnt_1,cnt_2;
string s,w;
int main()
{
cin>>q;
cin>>s;
cin>>w;
for (long long i=0;i<q;i++)
{
if (w[i]=='1')
cnt_1++;
else
cnt_2++;
}
long long len=s.size()-1;
if (cnt_1%2==1)
{
int l=0,r=len;
while (l<r)
{
char tmp=s[l];
s[l]=s[r];
s[r]=tmp;
l++;
r--;
}
}
if (cnt_2%2==1)
{
for (long long i=0;i<=len;i++)
{
if (s[i]=='1')
s[i]='0';
else
s[i]='1';
}
}
cout<<s;
}
也是相当的简单好吧。
后记
制作不易,不喜勿喷,谢谢!
\(MADE IN CHINA\)