2013年长春现场赛的B题。当时没有仔细看题目提示上的式子,非常遗憾地错过了这道其实比较水的题。
题目大意是输入一个十进制数,要求输出用φ进制表示的该数,φ是黄金比例数1.61803399......。
样例输入输出里给的是:
Sample Input
1
2
3
6
10
Sample Output
1
10.01
100.01
1010.0001
10100.0101
题目hint里给了两个式子:“φ + 1 = φ ^ 2” 和 “2 * φ ^ 2 = φ ^ 3 + 1”
如果将两式左右都乘上φ ^ n-2,就得到 “φ ^ (n - 1) + φ ^ (n - 2) = φ ^ n” 和 “2 * φ ^ n = φ ^ (n + 1) + φ ^ (n - 2)”
第一个式子可以表示φ进制数在任意两位上遇到连续的1,即11,都可以转化为100。
例如样例里2的φ进制表示为10.01,那么3就是11.01,题目要求输出里不能有连续的1,所以根据以上法则转化为100.01。
第二个式子可以表示φ进制数在任意一位上的2,都可以转化为1001。
例如4的φ进制表示为101.01,5就可以表示为102.01,根据那两个式子转化之后得1000.1001。
依此类推得6的φ进制表示为1001.101,转化得到1010.001
当然,题目给的数据范围是10^9,不能直接从1开始一个一个推着算,所以只要根据数据范围将2^0到2^29的φ进制表示算出来就行了。
拿6举例:6=4+2
2的φ进制表示:10.01
4的φ进制表示:101.01
那么6就是 10.01 + 101.01 = 111.02
111.02 -> 1001.02 -> 1001.1001 -> 1010.0001
现场的时候一方面没有仔细理解题意,也没有仔细思考提示中的那两个式子该怎么用,以为还要用到浮点运算,其实只要理清思路就是单纯的模拟了。
下面附上我的源码:
#include <cstdio> #include <cstring> #define LEN 100 #define HLE 50 using namespace std; typedef struct fbn { int a[LEN]; int pn; void init() { memset(a, 0, sizeof(a)); pn = 0; } void print() { bool b = false; for (int i = 0; i < HLE; i++) { if (a[i] != 0) b = true; if (b == true) printf("%d", a[i]); } if (pn != 0) { printf("."); for (int i = 0; i < pn; i++) printf("%d", a[i + HLE]); } printf("\n"); } }FBN; bool check(FBN a) { bool t = true; for (int i = 0; i < LEN; i++) { if (a.a[i] > 1) {t = false; break;} if ((i != LEN - 1) && a.a[i] == 1 && a.a[i + 1] == 1) {t = false; break;} } return t; } FBN normalize(FBN a) { int t; do { for (int i = 0; i < LEN; i++) { if (a.a[i] > 1) { t = a.a[i] / 2; a.a[i] %= 2; a.a[i - 1] += 1; a.a[i + 2] += 1; } if ((i != LEN - 1) && a.a[i] == 1 && a.a[i + 1] == 1) { a.a[i - 1] += 1; a.a[i] = 0; a.a[i + 1] = 0; } } } while (!check(a)); for (int i = LEN - 1; i >= HLE; i--) { if (a.a[i] != 0) { a.pn = i - HLE + 1; break; } } return a; } FBN add(FBN a, FBN b) { FBN ans; ans.init(); for (int i = 0; i < LEN; i++) { ans.a[i] = a.a[i] + b.a[i]; } ans = normalize(ans); return ans; } int main() { int n, i; FBN twob[30], ans; for (i = 0; i < 30; i++) twob[i].init(); twob[0].a[HLE - 1] = 1; twob[0].pn = 0; for (i = 1; i < 30; i++) { twob[i] = add(twob[i - 1], twob[i - 1]); } while (scanf("%d", &n) != EOF) { i = 0; ans.init(); while (n > 0) { if ((n & 1) == 1) ans = add(ans, twob[i]); n >>= 1; i++; } ans.print(); } return 0; }