【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\)

posted @ 2024-03-25 19:46  Hongfr  阅读(30)  评论(2)    收藏  举报