推荐测评/题面端:
解法:
题目中说,隔 2 个苹果拿一个苹果,意味着从左侧开始在每 3 个苹果中拿出第一个苹果。
再来看看数据范围:,而我们知道,两个答案都不会大于 ,这样用不上 类型,用 就够了。
50分做法:
全模拟,我们不妨用vector来存储信息。
代码十分好懂,要说的写在注释里了。
时间复杂度:;空间复杂度:。
#include<bits/stdc++.h>
using namespace std;
vector<int>vec;
int n,ans1,ans2;
int main()
{
//建议使用较快的读入、输出方式。
scanf("%d",&n);
for(int i=1;i<=n;i++)
vec.push_back(i);//将第i个苹果放进队列。
while(vec.size()>0)//队列里还有苹果的话
{
ans1++;//总操作次数加一
for(int i=0;i<vec.size();i+=2)//枚举每个要拿掉的苹果
//本来 i 应该 +3,但是因为每轮循环里都会拿掉掉一个苹果,所以+2
{
if(vec[i]==n)//如果要拿掉的苹果编号为 n
ans2=ans1;
vec.erase(vec.begin()+i);//删掉该苹果
}
}
printf("%d %d",ans1,ans2);
return 0;
}
90分做法:
我们发现前面的代码TLE了,因为vector有点慢,我们用普通的数组试试。
代码与之前的十分相似,也是模拟,就不过多做解释了。
#include<bits/stdc++.h>
using namespace std;
int n,total,ans1,ans2,t;
bool a[1000000005];
//a[i]=false表示还没被取走,反之表示被取走了。
int main()
{
scanf("%d",&n);
total=n;//当前还剩多少苹果。
while(total)//苹果还有剩
{
ans1++;
int j=0;//这是每 3 个苹果中的第几个苹果。
t=0;//这一轮中删掉了多少苹果。
for(int i=1;i<=n;i++)
if(!a[i])//编号为 i 的苹果还没被取走
{
j++;
j=(j==3?0:j);
t+=a[i]=(j==1?1:a[i]);
ans2=(i==n?ans1:ans2);
}
total-=t;
}
printf("%d %d",ans1,ans2);
return 0;
}
满分做法:
其实还是很简单的,难度大概就 普及-,其实很好想,只要知道每次删了几个苹果,以及每次有没有删最后一个苹果就行了。这两个加粗的问题用几个数组记录就好了。详见代码。
#include<bits/stdc++.h>
using namespace std;
int n,total,i,ans2,k;
int main()
{
scanf("%d",&n);
total=n;//当前剩几个苹果
while(total>0)//还有苹果
{
i++;
if(total%3==1&&k==0)//如果最后一个被取走了
{
//备注:因为我不知道最后一个苹果还是不是编号为 n 的苹果
//所以不妨找个数组 k 记一下最后一个苹果还是不是编号为 n 的苹果
k=1,ans2=i;
}
//计算还有多少苹果。
if(total%3==0)
{
total=total/3*2;
}
else
{
total=total/3*2+(total%3-1);
}
}
printf("%d %d",i,ans2);
return 0;
}