模拟 - Death to Binary? - POJ 2116
题意:
斐 波 那 契 数 列 : 斐波那契数列: 斐波那契数列:
F n = F n − 1 + F n − 2 , F 0 = 1 , F 1 = 2 , n ≥ 2. F_n=F_{n-1}+F_{n-2},F_0=1,F_1=2,n\ge2. Fn=Fn−1+Fn−2,F0=1,F1=2,n≥2.
给 定 一 个 01 串 S , 用 斐 波 那 契 数 列 来 表 示 十 进 制 数 , 给定一个01串S,用斐波那契数列来表示十进制数, 给定一个01串S,用斐波那契数列来表示十进制数,
例 如 110100 1 F i b = F 0 + F 3 + F 5 + F 6 = 1 + 5 + 13 + 21 = 40 。 例如1101001_{Fib }= F_0 + F_3 + F_5 + F_6 = 1 + 5 + 13 + 21 = 40。 例如1101001Fib=F0+F3+F5+F6=1+5+13+21=40。
每 个 整 数 都 可 以 以 此 基 数 表 示 , 但 不 一 定 以 唯 一 的 方 式 表 示 。 例 如 40 也 可 以 表 示 为 1000100 1 F i b 。 但 是 , 对 于 任 何 整 数 , 都 有 一 个 不 包 含 两 个 相 邻 数 字 1 的 唯 一 表 示 形 式 我 们 将 此 表 示 形 式 称 为 规 范 。 例 如 , 1000100 1 F i b 是 40 的 标 准 斐 波 那 契 表 示 形 式 。 每个整数都可以以此基数表示,但不一定以唯一的方式表示。\\例如40也可以表示为10001001_{Fib}。\\但是,对于任何整数,都有一个不包含两个相邻数字1的唯一表示形式\\我们将此表示形式称为规范。例如,10001001 _{Fib}是40的标准斐波那契表示形式。 每个整数都可以以此基数表示,但不一定以唯一的方式表示。例如40也可以表示为10001001Fib。但是,对于任何整数,都有一个不包含两个相邻数字1的唯一表示形式我们将此表示形式称为规范。例如,10001001Fib是40的标准斐波那契表示形式。
输入:
多 组 测 试 数 据 , 每 组 包 括 共 两 个 01 串 X 和 Y 。 多组测试数据,每组包括共两个01串X和Y。 多组测试数据,每组包括共两个01串X和Y。
输出:
计 算 X + Y 的 斐 波 那 契 表 示 , 以 竖 式 计 算 的 形 式 呈 现 出 来 , 计算X+Y的斐波那契表示,以竖式计算的形式呈现出来, 计算X+Y的斐波那契表示,以竖式计算的形式呈现出来,
X 的 规 范 形 式 + Y 的 规 范 形 式 _ _ _ _ _ _ _ _ _ _ _ _ 答 案 的 规 范 形 式 \qquad X的规范形式\\+ \quad Y的规范形式\\\qquad\_\_\_\_\_\_\_\_\_\_\_\_\\\qquad答案的规范形式 X的规范形式+Y的规范形式____________答案的规范形式
Sample Input
11101 1101
1 1
Sample Output
100101
+ 10001
-------
1001000
1
+ 1
--
10
数据范围:
∣ X ∣ , ∣ Y ∣ ≤ 40 |X|,|Y|\le 40 ∣X∣,∣Y∣≤40
分析:
由 于 X , Y 的 长 度 很 小 , 就 可 以 暴 力 乱 搞 。 由于X,Y的长度很小,就可以暴力乱搞。 由于X,Y的长度很小,就可以暴力乱搞。
如 何 将 一 个 01 串 转 化 为 规 范 形 式 ? 如何将一个01串转化为规范形式? 如何将一个01串转化为规范形式?
先 将 其 转 化 为 10 进 制 数 V , 再 从 十 进 制 V 转 化 为 规 范 形 式 。 先将其转化为10进制数V,再从十进制V转化为规范形式。 先将其转化为10进制数V,再从十进制V转化为规范形式。
① 、 转 化 为 10 进 制 数 : 字 符 串 的 第 i 位 是 1 , 就 累 加 上 F i 。 ①、转化为10进制数:字符串的第i位是1,就累加上F_i。 ①、转化为10进制数:字符串的第i位是1,就累加上Fi。
② 、 转 化 为 规 范 形 式 : 从 大 到 小 枚 举 斐 波 那 契 数 列 的 第 i 项 , 若 V ≥ F i , 就 减 去 F i , 同 时 添 加 一 个 1 , 否 则 添 加 1 个 0 。 ②、转化为规范形式:从大到小枚举斐波那契数列的第i项,若V\ge F_i,就减去F_i,同时添加一个1,否则添加1个0。 ②、转化为规范形式:从大到小枚举斐波那契数列的第i项,若V≥Fi,就减去Fi,同时添加一个1,否则添加1个0。
规 范 形 式 即 不 存 在 连 续 的 1 , 下 说 明 ② 的 操 作 方 法 能 够 保 证 不 出 现 连 续 的 1 。 规范形式即不存在连续的1,下说明②的操作方法能够保证不出现连续的1。 规范形式即不存在连续的1,下说明②的操作方法能够保证不出现连续的1。
因 为 F n = F n − 1 + F n − 2 , n ≥ 2 , 因 为 我 们 是 从 大 到 小 枚 举 的 斐 波 那 契 数 列 的 第 i 项 , 因为F_n=F_{n-1}+F_{n-2},n\ge 2,因为我们是从大到小枚举的斐波那契数列的第i项, 因为Fn=Fn−1+Fn−2,n≥2,因为我们是从大到小枚举的斐波那契数列的第i项,
若 在 第 i − 1 位 和 第 i − 2 位 上 存 在 连 续 的 两 个 1 , 即 相 当 于 在 第 i 位 上 有 一 个 1 , 我 们 会 优 先 减 去 F i , 若在第i-1位和第i-2位上存在连续的两个1,即相当于在第i位上有一个1,我们会优先减去F_i, 若在第i−1位和第i−2位上存在连续的两个1,即相当于在第i位上有一个1,我们会优先减去Fi,
之 后 到 第 i − 1 位 时 , 1 就 不 存 在 了 。 之后到第i-1位时,1就不存在了。 之后到第i−1位时,1就不存在了。
注意:
用 空 字 符 串 进 行 操 作 ② 时 , 注 意 结 果 为 0 的 情 况 , 不 能 返 回 空 串 。 用空字符串进行操作②时,注意结果为0的情况,不能返回空串。 用空字符串进行操作②时,注意结果为0的情况,不能返回空串。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=50;
int f[N];
string a,b;
void Init()
{
f[0]=1, f[1]=2;
for(int i=2;i<N;i++) f[i]=f[i-1]+f[i-2];
}
string trans(string x,int & vx)
{
reverse(x.begin(),x.end());
vx=0;
int len=x.size();
for(int i=0;i<len;i++)
if(x[i]=='1')
vx+=f[i];
int tmp=vx;
string res="";
for(int i=40;i>=0;i--)
{
if(tmp-f[i]>=0)
{
tmp-=f[i];
res+='1';
}
else if(res!="") res+='0';
}
if(res=="") res="0";
return res;
}
int main()
{
Init();
while(cin>>a>>b)
{
int va=0, vb=0;
a=trans(a,va), b=trans(b,vb);
int la=a.size(), lb=b.size();
int vc=va+vb;
string ans="";
for(int i=40;i>=0;i--)
if(vc-f[i]>=0)
{
ans+='1';
vc-=f[i];
}
else if(ans!="") ans+='0';
if(ans=="") ans="0";
int len=ans.size();
for(int i=0;i<=len-la+1;i++) printf(" ");cout<<a<<endl;
printf("+");
for(int i=0;i<=len-lb;i++) printf(" ");cout<<b<<endl;
printf(" ");
for(int i=0;i<len;i++) printf("-");puts("");
cout<<" "<<ans<<endl;
puts("");
}
return 0;
}