该题为2013ICPC亚洲区预选赛长春站B题
http://acm.hdu.edu.cn/showproblem.php?pid=4814
题意很简单:给定一个十进制数,要求输出在(1+sqrt(5))/2进制中的数的表示。
这题做模拟赛的时候拿到有点摸不着头脑,第一直觉是想用java大数来做,但是后来发现样例中的每个结果计算出来都是整数,卡精度的方法其实是不可取的。
后来又因为发现1+1=10.01想到九进制转二进制,但是发现转换要写高精度,不好实现...
当时这题也就放下了。后来再看到这题才发现原来条件都在题目中清晰给出了。即:
1.相同位数相加 1+1=10.01
2.不同位数出现连续两个1 即11=100
直接看作是二进制的两种特殊运算来对待即可
由于二者互相独立
则类似3+2=20.02+1
而进一步对于20.02中的每一个2也进行处理,对于连续的两个1产生进位之后加上的1可能会出现新的2的情况,采用标记进行循环处理,直至无需处理符合要求。
一些处理:
为了防止处理前导0以及结尾0和小数点,直接define了小数点所在的位置,采用string输出
数组开太大会TLE 预先要估算数字大约会在100位(小数点前后各50位)
700ms,应该优化的空间还是有
code:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <cstdlib>
#define INF 0x3f3f3f3f
#define dem 50
using namespace std;
int i,p,l,j,n,m,head,tail;
int base[33][105];
int ans[105];
string si;
int main()
{
memset(base,0,sizeof(base));
base[0][dem]=1;
for (i=1;i<=32;i++)
{
for (j=1;j<=100;j++)
base[i][j]=base[i-1][j]*2;
do{
do{
p=0;
for (j=1;j<=100;j++)
if (base[i][j]>1) {
p=1;
base[i][j-1]+=base[i][j]/2;
base[i][j+2]+=base[i][j]/2;
base[i][j]=base[i][j]%2;}
}
while (p);
p=0;
for (j=100;j;j--)
if (base[i][j+1]==1&&base[i][j+2]==1)
{
p=1;
base[i][j+1]=base[i][j+2]=0;
base[i][j]+=1;
}
}
while(p);
}
while(scanf("%d",&n)!=EOF)
{
memset(ans,0,sizeof(ans));
m=n;
l=0;
while(m)
{
if (m%2)
{
for (j=1;j<=100;j++)
ans[j]+=base[l][j];
do{
do{
p=0;
for (j=1;j<=100;j++)
if (ans[j]>1)
{
p=1;
ans[j-1]+=ans[j]/2;
ans[j+2]+=ans[j]/2;
ans[j]%=2;
}
}
while (p);
p=0;
for (j=100;j;j--)
if (ans[j+1]==1&&ans[j+2]==1)
{
p=1;
ans[j+1]=ans[j+2]=0;
ans[j]+=1;
}
}
while(p);
}
m/=2;
l++;
}
for (i=0;i<=100;i++)
if (ans[i]) break;
head=i;
for (i=0;i<=100;i++)
if (ans[i]) tail=i;
for (i=head;i<=tail;i++)
{
printf("%d",ans[i]);
if (i==dem&&tail>dem) printf(".");
}
printf("\n");
}
return 0;
}