题目描述
小 Y 的桌子上放着 n 个苹果从左到右排成一列,编号为从 1 到 n。
小苞是小 Y 的好朋友,每天她都会从中拿走一些苹果。每天在拿的时候,小苞都是从左侧第 1 个苹果开始、每隔 2 个苹果拿走 1 个苹果。随后小苞会将剩下的苹果按原先的顺序重新排成一列。
小苞想知道,多少天能拿完所有的苹果,而编号为 n 的苹果是在第几天被拿走的?
输入输出
- 输入的第一行包含一个正整数 n,表示苹果的总数。
- 输出一行包含两个正整数,两个整数之间由一个空格隔开,分别表示小苞拿走所有苹果所需的天数以及拿走编号为 n 的苹果是在第几天。
- 样例
样例输入1
8
样例输出1
5 5
样例输入2
1000
样例输出2
16 1
- 数据范围
题目分析
从第1个苹果开始,每隔2个拿走1个苹果。这样的拿法实际上等价于把苹果每3个分一堆,在里面拿第一1个。也就是每次拿第 \(3k+1\) 个苹果\((k=0,1,2,……)\)。注意不是原本编号为 \(3k+1\) 的苹果,而是桌子上现有的苹果的第 \(3k+1\) 个。
如果桌子上现有的苹果数 \(n\) 恰好能被3整除,那么正好是每3个拿1个,拿走的苹果数目是 \(\frac{1}{3}n\);
如果不能被3整除,由于每次拿的是3个苹果里的第一个,所以每3个一堆拿走第1个之后,还要在不足3个的那一堆拿走第一个,最后拿走的苹果数目是 \(\lfloor\frac{n}{3}\rfloor+1\);
计算总天数只需每次从现有的苹果数中减去每天拿走的个数,然后天数+1,直到 \(n≤0\) 即可。
取到苹果 \(n\) 是第几天
对于苹果 $n $,要想正好在某一天取到,它当天必须位于第 \(3k+1\) 个苹果的位置。并且由于它是原先所有苹果中最后一个,取的时候仅有两种可能:要么取到的是苹果 \(n\),要么取到的是苹果 \(n\) 之前的苹果。所以,没取走苹果n之前它会一直在最后的位置,据此得到取到苹果 \(n\) 的必要条件是,当天桌子上应当有且仅有 \(3k+1\) 个苹果。
而在所有“桌子上有且仅有 \(3k+1\) 个苹果”的日子里,还必须保证是首次出现 \(3k+1\) 个苹果的那天。否则苹果 \(n\) 已经被取走了,当天取到的虽然是桌子上现有的最后一个苹果,但不是原先的苹果里的最后一个(即苹果 \(n\) )
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n;
cin >> n;
int apple_num = n;
int day = 0,day_n = 0;
while(n>0) {
day++; // 总天数
if(n%3) {
// 因为隔2拿1(每3个拿最后1个),所以想要拿到第n个,必须剩余水果数除3恰好余1
// 并且必须是之前没有出现过这种情况,否则第n个拿走了,拿到的不是第n个
if(n%3==1&&!day_n) day_n = day;
n-=n/3+1; // 这一轮拿走的苹果数
}
// 剩余水果数能被3整除,则直接拿走1/3的水果
else n-=n/3;
}
cout << day << ' ' << day_n;
return 0;
}