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;
}
0 条讨论