该题为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; }