AtCoderBeginnerContest397(A - Thermometer、B - Ticket Gate、C - Variety Split Easy、D - Cubes)题目讲解

OMRONCorporationProgrammingContest2025(AtCoderBeginnerContest397)

前言

又更新AtCoder Beginner Contes 的题目讲解啦!!
希望能给诸位带来帮助。

在这里插入图片描述


话不多说,开始翻译:

A - Thermometer←点击看翻译

这题只需要运用判断语句。

解题思路

体温为N;

  • N≧ 38.0 38.0 38.0 ∘ {}^\circ C:“高烧”,输出1。
  • 38.0 38.0 38.0 ∘ {}^\circ C>N≧ 37.5 37.5 37.5 ∘ {}^\circ C:“低烧”,输出2。
  • N< 37.5 37.5 37.5 ∘ {}^\circ C:“正常”,输出3。
代码:
#include<bits/stdc++.h>

using namespace std;

int main() {
	float n;
	cin>>n;
	if(n>=38.0)
	{
		cout<<1<<endl;
	}
	else if(n>=37.5){
		cout<<2<<endl;
	}
	else{
		cout<<3<<endl;
	}
	return 0;
}

B - Ticket Gate←点击看翻译

方法思路:

看到这题,许多人都会想到用字符串的插入函数insert,但对于初学者来说还有一种简单的思路。

首先分别定义三个变量来存储当前字符串长度、答案、当前判断位置。
通过循环挨个判断字符是否正确,如果正确则向后继续判断(即位置+1),如果错误则答案+1且长度+1,下一次继续访问这个点。当判断完所有字符,如果长度是奇数,则答案+1。
在这里插入图片描述
如上图所示↑,现在的位置是奇数应当是i,所以o是错的,则长度+1,答案+1(相当于在o前面插入一个i)。

//中间步骤省略


最后如下↓
在这里插入图片描述

//注意!!!橙色箭头并不是插入!!!!!

代码:
#include<bits/stdc++.h>

using namespace std;

int main() {
	string n;
	cin>>n;
	int ans=0,l;
	l=n.size();
	for(int i=0,j=1;i<n.size();)
	{
		if(j==1)
		{
			if(n[i]=='i')
			{
				j=0;
				i++;
			}
			else{
				j=0;
				ans+=1;
				l+=1;
			}
		}
		else if(j==0)
		{
			if(n[i]=='o')
			{
				j=1;
				i++;
			}
			else{
				j=1;
				ans+=1;
				l+=1;
			}
		}
		//cout<<ans<<' '<<i<<' '<<j<<endl;
	}
	if(l%2==1)
	{
		cout<<ans+1;
	}
	else{
		cout<<ans;
	}
	return 0;
}

C - Variety Split Easy←点击看翻译

解题思路
  1. 整体统计:首先统计整个数组的元素出现次数,并计算总的不同元素数量(作为初始右子数组的不同数)。
  2. 动态调整:从左到右遍历每个可能的分割点,将当前元素从右子数组移到左子数组:
    • 右子数组更新:若该元素在右子数组只剩一个实例,移除后右子数组的不同数减1。
    • 左子数组更新:若该元素首次加入左子数组,左子数组的不同数加1。
  3. 实时计算最大值:每次移动后,计算左右子数组的不同数之和,并更新最大值。
代码:
#include<bits/stdc++.h>
using namespace std;
int a[300005],b[300005],c[300005]; // a存储原数组,b记录右半元素出现次数,c记录左半元素出现次数

int main() {
    int n, x=0, y=0, ans=0; // x:左半不同数,y:右半不同数,ans:答案
    cin >> n;
    for(int i=1; i<=n; i++) {
        cin >> a[i];
        if(b[a[i]] == 0) y++; // 首次出现,右半不同数+1
        b[a[i]]++; // 统计右半元素出现次数
    }
    for(int i=1; i<=n-1; i++) { // 遍历分割点i(左半结束位置)
        // 处理右半部分
        if(b[a[i]] == 1) y--; // 当前元素是右半最后一个,移除后右半不同数-1
        // 处理左半部分
        if(c[a[i]] == 0) x++; // 当前元素首次加入左半,左半不同数+1
        b[a[i]]--; // 从右半移除该元素
        c[a[i]]++; // 加入左半
        ans = max(ans, x + y); // 更新最大值
    }
    cout << ans;
    return 0;
}

D - Cubes←点击看翻译

为了解决这个问题,我们需要找到两个正整数 ( x ) 和 ( y ) 使得 ( x3 - y3 = N )。通过数学推导和优化,我们可以有效地解决这个问题。

方法思路

  1. 数学推导:利用立方差公式 x3 - y3 = (x - y)(x2 + xy + y2 ),我们可以将问题转化为寻找两个因数 a 和 b 使得 a * b = N ,其中 a = x - y 和 b = x2 + xy + y2

  2. 因数遍历:遍历所有可能的因数 a (从 1 到 N 的立方根),检查 a 是否为 N 的因数,并计算对应的 b = N / a 。

  3. 二次方程解:对于每个有效的因数对 (a, b),检查是否存在整数 m 使得 3y2 + 3ay + a2 = b 有正整数解。通过解二次方程并验证解的条件,确定是否存在有效的 y 和 x 。

解决代码

#include <iostream>
#include <cmath>
using namespace std;

typedef long long ll;

ll cube_root(ll N) {
    if (N == 0) return 0;
    ll low = 1, high = 1e6; // 因为N最大是1e18,立方根最多是1e6
    while (low <= high) {
        ll mid = (low + high) / 2;
        if (mid > N / (mid * mid)) {
            high = mid - 1;
        } else {
            low = mid + 1;
        }
    }
    return high;
}

int main() {
    ll N;
    cin >> N;

    ll max_a = cube_root(N);

    for (ll a = 1; a <= max_a; ++a) {
        if (N % a != 0) continue;
        ll b = N / a;

        if (4 * b < a * a) continue;

        ll temp = 4 * b - a * a;
        if (temp % 3 != 0) continue;
        temp /= 3;

        ll m = sqrt(temp);
        if (m * m != temp) continue;

        if (m <= a) continue;

        if ((m - a) % 2 != 0) continue;

        ll y = (m - a) / 2;
        ll x = (m + a) / 2;

        if (y > 0) {
            cout << x << " " << y << endl;
            return 0;
        }
    }

    cout << -1 << endl;
    return 0;
}

代码解释

  1. cube_root 函数:通过二分法计算 N 的立方根,确定遍历的上限,减少不必要的计算。
  2. 主循环:遍历所有可能的因数 a 并检查其是否为 N 的因数。对于每个有效的因数对 (a, b) ,验证是否存在符合条件的整数解。
  3. 条件检查:检查二次方程的解是否为整数,并验证解的正整数条件,最终输出结果或判断无解。

该方法通过数学优化和高效的因数遍历,确保在合理时间内处理大数范围内的输入。


觉得还不错,可以点点红心和关注,欢迎在评论区评论
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wangyuxuan1029

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值