Skip to main content
Original206 words1 min

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

Summary

n 个苹果排成一列,每天从左起第 1 个开始每隔两个拿走一个,剩余按原序重排,求拿完所有苹果的天数以及最右那个(编号 n)在第几天被拿走。每天剩 n 个会拿走 n 除以 3 上取整个、剩下 2n 除以 3 下取整个,约去掉三分之一,故 O(log n) 天拿完,直接模拟。最右苹果始终在末位,当且仅当某天剩余数模 3 余 1 时被拿走,首次遇到即答案。时间复杂度 O(log n)。

题意简述​

nn 个苹果排成一列。每天从左起第 11 个开始、每隔 22 个拿走 11 个(即拿走第 1,4,7,…1,4,7,\dots 个),剩下的按原顺序重排。求拿完所有苹果的天数,以及编号 nn(最右)的苹果在第几天被拿走。

解题思路​

某天剩 nn 个苹果时,拿走的是位置 1,4,7,…1,4,7,\dots,共 ⌈n/3⌉\lceil n/3\rceil 个,剩 ⌊2n/3⌋\lfloor 2n/3\rfloor 个。每天约去掉三分之一,故 O(log⁡n)O(\log n) 天就能拿完,直接模拟天数即可。

最右的苹果始终在末位,那天它的位置就是当前剩余个数 nn,因此它被拿走当且仅当 n≡1(mod3)n\equiv1\pmod 3。模拟中第一次遇到 n mod 3=1n\bmod 3=1 的那天,就是它被拿走的日子。

用 ⌈n/3⌉=⌊(n+2)/3⌋\lceil n/3\rceil=\lfloor(n+2)/3\rfloor 避免浮点。

时间复杂度为 O(log⁡n)O(\log n)。

参考代码​

250 Bcpp
#include <bits/stdc++.h>
using namespace std;

int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin>>n;
int day=0,ans=0;
while(n)
{
day++;
if(!ans&&n%3==1)ans=day;
n-=(n+2)/3;
}
cout<<day<<' '<<ans<<'\n';
return 0;
}