2023 csp—j 赛后反思

文章介绍了如何用Python编程解决一个关于苹果取走问题的算法,通过整除和余数分析计算天数和特定苹果被取走的日期。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

T1 小苹果

【题目描述】

        小Y的桌子上放着n个苹果从左到右排成一列,编号为从1到n。

        小苞是小Y的好朋友,每天她都会从中拿走一些苹果。 每天在拿的时候,小苞都是从左侧第1个苹果开始、每隔2个苹果拿走1个苹果。 随后小苞会将剩下的苹果按原先的顺序重新排成一列。

        小苞想知道,多少天能拿完所有的苹果,而编号为n的苹果是在第几天被拿走的?

输出格式

        输出的第一行包含一个正整数n,表示苹果的总数。

【输出格式】

        输出一行包含两个正整数,两个整数之间由一个空格隔开,分别表示小苞拿走所有
苹果所需的天数以及拿走编号为n的苹果是在第几天。

题目分析

        因为题目要求苹果数量有 10^9 个,所以模拟法效率会很低,我们不能建立一个大数组或者链表,去模拟题目中的顺序一个一个取苹果。也不能使用递归,栈可能会爆掉。 

1. 拿走苹果的总天数

我们先分析多少天可以拿走所有苹果

分析题目的关键点,观察苹果是如何取的:每隔两个取走一个

这句话提醒我们,如果每3个苹果分成一组,那么就是每组的第一个苹果会被拿走。

So,任何一个数都可以表示为被3 整除的部分,和余数部分,也就是:

n = 3 * p + r

其中, 3*p 是可以被三整除的部分,r 是余数部分,0 <= r <3

因此,取苹果的过程可以看作,从 p 个分组中,每次取一个,从余数部分中(如果有的话),每次取一个。

因此每次取苹果的个数为:

if (r > 0) 
{
    n -= p + 1; // 每个组拿一个,余数组拿一个
} 
else 
{
    n -= p; // 每个组拿一个,没有余数组
}

需要注意的是,如果只有余数组了,每次只能拿一个苹果:

if (p > 0) 
{
    // 正常从所有组拿苹果
    ......
} 
else 
{
    // 仅从余数组拿苹果,每次只能拿一个
    n -= 1;
}

所以,完整的程序如下,使用 while 循环持续拿苹果,并记录天数即可:

#include <bits/stdc++.h>
typedef int intt;
#define int long long
using namespace std;

intt main() 
{
    int n = 0;
    cin >> n;

    int days = 0;

    // n = 3p + r;
    while (n > 0 ) 
	{
        int p = n / 3;
        int r = n % 3;
        if (p > 0) 
		{
            if (r > 0) 
			{
                // 每个组拿一个,余数组拿一个
                n -= p + 1;
            } 
			else {
                // 每个组拿一个
                n -= p;
            }
        }
		else {
            // 余数组一个一个拿
            n -= 1;
        }
        days++;
    }

    cout << days;
    return 0;
}

2. 第几天拿走最后一个苹果

考虑取苹果的过程,如果余数组苹果个数为 1, 那么这天就是取最后一个苹果的日子,

如果余数组苹果数量始终不为1, 那么最后一个苹果一定是最后一天拿走的。

因此,我们增加一个标志位,表示在取苹果的过程中,是否取走过最后一个,如果取走了,就记录天数;否则,就是最后一天。

if (p > 0) 
{
    if (r > 0) 
    {
        ......
        if (!flag && r == 1)
         {
            lastDay = days + 1;
            flag = true;
        }
    } 
    else 
    {
        ......
    }
} 
else 
{
    ......
}
if (!flag) 
{
      lastday = days
}

完整代码如下:

#include <bits/stdc++.h>
typedef int intt;
#define int long long
using namespace std;
intt main() 
{
    int n = 0;
    cin >> n;

    int days = 0;
    int lastDay = 0;
    bool flag = false;

    // n = 3p + r;
    while (n > 0 ) 
	{
        int p = n / 3;
        int r = n % 3;
        if (p > 0) 
		{
            if (r > 0) 
			{
                // 每个组拿一个,余数组拿一个
                n -= p + 1;
                if (!flag && r == 1) 
				{
                    lastDay = days + 1;
                    flag = true;
                }
            }
			else 
			{
                // 每个组拿一个
                n -= p;
            }
        } 
		else 
		{
            // 余数组一个一个拿
            n -= 1;
        }
        days++;
        if (!flag) 
		{
            lastDay = days;
        }
    }

    cout << days << ' ' << lastDay;
    return 0;
}

 

总结:

“任何一个整数,可以表示为被三整除的部分加上余数部分”:

n = 3 * p + r
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值