/blog/oi

P9748 [CSP-J 2023] 小苹果 题解

P9748 [CSP-J 2023] 小苹果 题目描述 小 Y 的桌子上放着 $n$ 个苹果从左到右排成一列,编号为从 $1$ 到 $n$。 小苞是小 Y 的好朋友,每天她都会从中拿走一些苹果。 每天在拿的时候,小苞都是从左侧第 $1$ 个苹果开始、每隔 $2$ 个苹果拿走 $1$ 个苹果。随后小苞会将剩下的苹果按原先的顺序重新排成一列。 小苞想知道,多少天...

W WillZhong RichMan 16 views min read OI

P9748 [CSP-J 2023] 小苹果

题目描述

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

小苞是小 Y 的好朋友,每天她都会从中拿走一些苹果。

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

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

输入格式

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

输出格式

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

输入输出样例 #1

输入 #1

8

输出 #1

5 5

说明/提示

【样例 $1$ 解释】

小苞的桌上一共放了 $8$ 个苹果。
小苞第一天拿走了编号为 $1$、$4$、$7$ 的苹果。
小苞第二天拿走了编号为 $2$、$6$ 的苹果。
小苞第三天拿走了编号为 $3$ 的苹果。
小苞第四天拿走了编号为 $5$ 的苹果。
小苞第五天拿走了编号为 $8$ 的苹果。

【样例 $2$】

见选手目录下的 apple/apple2.in 与 apple/apple2.ans。

【数据范围】

对于所有测试数据有:$1\leq n\leq 10^9$。

测试点 $n\leq$ 特殊性质
$1\sim 2$ $10$
$3\sim 5$ $10^3$
$6\sim 7$ $10^6$
$8\sim 9$ $10^6$
$10$ $10^9$

特殊性质:小苞第一天就取走编号为 $n$ 的苹果。

这个题类似于约瑟夫问题,但$n\leq 10^9$,模拟只能通过$n\leq 10^6$的数据

#include <bits/stdc++.h>
using namespace std;
const int N = 1e9+5;
bool vis[N];
int main(){
    //freopen("apple.in", "r", stdin);
    //freopen("apple.out", "w", stdout);
    int n;
    cin >> n;
    int rst = n;
    int t;
    int ans = 0;
    int res;
    while(rst){
        bool taken = false;
        t=-1;
        for(int i = 1;i <= n;i++){
            if(vis[i])continue;
            if(!taken || t==2){
                taken = true;
                vis[i] = true;
                if(i == n){
                    res = ans+1;
                }
                rst--;
            }
            t = (t+1)%3;
        }
        ans++;
    }
    cout << ans << ' ' << res;
}

考虑数学解法

当还有 $n$ 个苹果时,一共会拿走 $\lceil \frac{n}{3} \rceil$ 个苹果也就是(n+2)/3 个苹果 所以,循环解决

#include <bits/stdc++.h>
using namespace std;
int main(){
    int n;
    cin >> n;
    int cnt = 0;
    while(n > 0){
        cnt++;
        n -= (n+2)/3;
    }
    cout << cnt << ' ' << 1;
}

根据特殊性质,第二问等于 $1$ 所以这是 $20$ 分代码

考虑第二问第 $n$ 个苹果在被拿走前一直是最后一个苹果,所以它的编号可以在while循环过程中以n表示,当 $n\mod3 = 1$ 时刚好会取到最后一个苹果,所以使用res记录被拿走的时间 注意⚠️:当最后一个苹果被拿走后就不能再更新res

#include <bits/stdc++.h>
using namespace std;
int main(){
    int n;
    cin >> n;
    int cnt = 0, res=-1;
    while(n > 0){
        cnt++;
        if(n%3==1 && res==-1)res = cnt;
        n -= (n+2)/3;
    }
    cout << cnt << ' ' << res;
}
OI
All articles
Comments

0 条讨论

Please sign in to join the conversation.

No comments yet. Be the first to share.