「题解」P8588「JROI-8」雷雨天特别行动科
题目分析
本题题意不难理解,直接翻译题意即可得到朴素的算法:
//核心代码
while(k--)
{
n++;
if(!(n%3))
n/=3;
}
但难点在数据范围:
打表
由于时间复杂度与
\\先打一个小的表看看
n=114514,k=0~100
[114515 , 38172 , 38173 , 38174 , 12725 , 4242 , 4243 , 4244 , 1415 , 472 ,
473 , 158 , 53 , 18 , 19 , 20 , 7 , 8 , 3 , 4 , 5 , 2 , 1 , 2 , 1 , 2 ,
1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 ,
1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 ,
1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 ,
1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 , 1 , 2 ,
1 , 2 , 1]
本来想打一个数据量更大的表,但现在这个已经能看出规律了,我甚至怀疑直接输出1/2就能拿到一堆分数。那,为什么后面的数是1和2,并且呈周期变化呢?
分析
对于任意的
当
当
当
我们发现,当
当
此时,不论
综上,我们便得到了一个新的算法:若
在这里,我们每循环一次,就直接让
注意事项
-
开long long。
-
边界情况:
n,k = 0 。
代码实现
//核心代码
while(k>3&&n>2)
{
long long m=n%3;
if(!m)
{
n=n/3+1;
k-=3;
}
else if(m==1)
{
n=(n+2)/3;
k-=2;
}
else if(m==2)
{
n=(n+1)/3;
k--;
}
}
//将n缩小,或者k足够小可以直接算
if(k<=3) //k足够小
while(k--)
{
n++;
if(!(n%3))n/=3;
}
else //或者n为0,1,2
{
if(!n)n++,k--;//n为0
if(k%2)n=3-n;//n为1,2,找规律直接出结果
}
cout<<n<<endl;
尾声
这是我退役以来,写的第一道题,也是第一篇题解。
感谢 @MX_DMX ,将我重新拉回算法的世界。纵使没有考上理想的大学,纵使专业与计算机没啥关联,但是,算法,依旧值得热爱。
OI之后,我们仍有无限的未来。