[ARC122C] Calculator
Posted PPL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ARC122C] Calculator相关的知识,希望对你有一定的参考价值。
前言
现在是22:10,离比赛结束过去了10分钟。
题目
题目大意:
给一个目标正整数 \\(N\\),你初始有两个数 \\(x=0,y=0\\) ,有四种操作:
- 将 \\(x\\) 替换为 \\(x+1\\)。
- 将 \\(y\\) 替换为 \\(y+1\\)。
- 将 \\(x\\) 替换为 \\(x+y\\)。
- 将 \\(y\\) 替换为 \\(x+y\\)。
要求在 \\(130\\) 次操作内将 \\(x\\) 变为目标数 \\(N\\)。
\\(1\\le N\\le 10^{18}.\\)
讲解
先放一个大数镇楼:679891637638612257。
我们先随便玩一玩发现,为了达到较大的目标状态,我们肯定需要反复使用操作 \\(3,4\\) 。
我反复用的操作顺序是 \\(4,3\\)。
假设初始状态为 \\((1,1)\\),那么之后的状态为:\\((1,2),(3,2),(3,5),(8,5),(8,13)...\\)
很显然的斐波拉契数列。
自然我们想到将 \\(N\\) 拆分为多个斐波拉契数相加,在适当的时机加上 \\((1,1)\\),当然根据斐波拉契数位置的奇偶性不同,我们也可能要加上 \\((2,1)\\)。
也就是说我们将 \\(x\\) 和 \\(y\\) 也拆分为多个斐波拉契数。
比如我们看这个例子:\\(N=11=8+3\\)。
\\((0,0;0,0),(0,1;0,1),(0,1;0,2),(0,3;0,2),(1,3;1,2),(1,3;2,5),(3,8;2,5).\\)
分号前为 \\(x\\),之后为 \\(y\\)。
最终状态:\\(x=8+3=11,y=2+5=7.\\)
到这里,我们的思路已经基本成型,但是这样还不够,细节上还需要优化,不然会被卡。
比如我们并不需要加上 \\((1,1)\\),因为 \\((0,1)\\) 经过一轮 \\(4,3\\) 后可以变成 \\((1,1)\\),\\((1,0)\\) 经过一轮 \\(4,3\\) 后可以变成 \\((2,1)\\)。详见代码。
代码
//12252024832524
#include <cstdio>
#include <cstring>
#include <algorithm>
#define TT template<typename T>
using namespace std;
typedef long long LL;
const int MAXN = 100005;
LL n,f[MAXN];
LL Read()
{
LL x = 0,f = 1;char c = getchar();
while(c > \'9\' || c < \'0\'){if(c == \'-\')f = -1;c = getchar();}
while(c >= \'0\' && c <= \'9\'){x = (x*10) + (c^48);c = getchar();}
return x * f;
}
TT void Put1(T x)
{
if(x > 9) Put1(x/10);
putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
if(x < 0) putchar(\'-\'),x = -x;
Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}
int c[MAXN],tot,ans[MAXN],anstot;
void Add(int x){ans[++anstot] = x;}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read();
f[1] = 1; f[2] = 2;
for(int i = 3;i <= 88;++ i) f[i] = f[i-1] + f[i-2];
for(int i = 88;i >= 1;-- i) if(n >= f[i]) c[++tot] = i,n -= f[i];
for(int i = 1;i <= tot;++ i)
{
if(i == tot)
{
if(c[tot] & 1) Add(2);
else Add(1);
for(int j = 1;j <= (c[tot]+1) / 2;++ j) Add(4),Add(3);
}
else
{
if(c[i] & 1) Add(2);
else Add(1);
for(int j = 1;j <= ((c[i]+1)/2-(c[i+1]+1)/2);++ j) Add(4),Add(3);
}
}
Put(anstot,\'\\n\');
LL x = 0,y = 0;
for(int i = 1;i <= anstot;++ i)
{
Put(ans[i],\'\\n\');
if(ans[i] == 1) x++;
else if(ans[i] == 2) y++;
else if(ans[i] == 3) x += y;
else y += x;
}
Put(anstot,\'\\n\');
return 0;
}
//679891637638612257
后记
赛时因为造了一个大于 \\(10^{18}\\) 的数,操作数达到 \\(132\\) 而怀疑人生。
不过赛时人确实有点麻了,想什么都不清楚,迷迷糊糊地就开始敲代码,结果WA到怀疑人生。
倦了。
以上是关于[ARC122C] Calculator的主要内容,如果未能解决你的问题,请参考以下文章