本题解搬自 zimpha’s blog:Zeckendorf Arithmetic。
- 【题目链接】
- 【解题方法】
题目中的整数表示方式其实就是Zeckendorf representation
。
这一题实际上就是做加法。
首先,我们像高精加一样,直接把两个数的Zeckendorf representation
加起来。就是,一位一位的加起来。拿样例举例,加完了之后像这样:1 1 0 2 0
(题目中输入是从低位到高位,这里采用从高位到低位)。
然后,我们考虑把那些不合法的地方消去。具体来讲,从高到低遍历。我们的首要任务是把 2 2 2 与 3 3 3 消去。当然,本来是没有 3 3 3 的。不过,我们在把 2 2 2 消去的过程中,可能会把某个 2 2 2 加 1 1 1。如果我们用 x \color{brown}x x 代表 x + 1 x+1 x+1,规则是这样的:
020 x → 100 x 030 x → 110 x 021 x → 110 x 012 x → 101 x \begin{aligned} 020x&\to100{\color{brown}x}\\030x&\to110{\color{brown}x}\\021x&\to110 x\\012x&\to 101x \end{aligned} 020x030x021x012x→100x→110x→110x→101x
当然,我们可能要特殊处理最后几位。不过,如果我们把 F 0 = 1 F_0=1 F0=1 和 F − 1 = 0 F_{-1}=0 F−1=0 加入表示中,我们就可以不用特殊处理。不过,如果表示中含有 F − 1 F_{-1} F−1,那直接忽略就行了。如果含有 F 0 F_{0} F0 呢?我们稍后处理。
现在我们处理连续的 1 1 1。我们用两次 011 → 100 011\to100 011→100,第一次从高位到低位,第二次从低位到高位。第一次做完后,没有连续的 3 3 3 个 1 1 1,表示中不可能同时含有 F 0 F_0 F0 和 F 1 F_1 F1,所以如果表示中有 F 0 F_0 F0 那么直接把它变成 F 1 F_1 F1 即可。在这个基础上,第二遍直接做即可。
- 【代码实现】
#include <iostream>
#include <array>
using namespace std;
array<int,1000002> fib_rep;
int main(int argc,char* argv[],char* envp[])
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int cnt;
cin>>cnt;
for(int i=2;i<cnt+2;i++)
cin>>fib_rep[i];
cin>>cnt;
for(int i=2;i<cnt+2;i++)
cin>>fib_rep[0],fib_rep[i]+=fib_rep[0];
fib_rep[0]=0;
for(int i=1000001;i>=2;i--)
if(fib_rep[i]==0&&fib_rep[i-1]==2&&fib_rep[i-2]==0)
fib_rep[i]=1,fib_rep[i-1]=0,fib_rep[i-2]=0,fib_rep[i-3]++;
else if(fib_rep[i]==0&&fib_rep[i-1]==3&&fib_rep[i-2]==0)
fib_rep[i]=1,fib_rep[i-1]=1,fib_rep[i-2]=0,fib_rep[i-3]++;
else if(fib_rep[i]==0&&fib_rep[i-1]==2&&fib_rep[i-2]==1)
fib_rep[i]=1,fib_rep[i-1]=1,fib_rep[i-2]=0;
else if(fib_rep[i]==0&&fib_rep[i-1]==1&&fib_rep[i-2]==2)
fib_rep[i]=1,fib_rep[i-1]=0,fib_rep[i-2]=1;
for(int i=1000001;i>=2;i--)
if(fib_rep[i]==0&&fib_rep[i-1]==1&&fib_rep[i-2]==1)
fib_rep[i]=1,fib_rep[i-1]=0,fib_rep[i-2]=0;
if(fib_rep[1]==1)
fib_rep[2]=1;
for(int i=4;i<=1000001;i++)
if(fib_rep[i]==0&&fib_rep[i-1]==1&&fib_rep[i-2]==1)
fib_rep[i]=1,fib_rep[i-1]=0,fib_rep[i-2]=0;
int ptr;
for(ptr=1000001;!fib_rep[ptr];ptr--);
cout<<ptr-1<<' ';
for(int i=2;i<=ptr;i++)
cout<<fib_rep[i]<<' ';
return 0;
}