HDOJ-1041 Computer Transformation(找规律+大数运算)
http://acm.hdu.edu.cn/showproblem.php?pid=1041
有一个初始只有一个1的串 每次都按①0 -> 10;②1 -> 01;这两条规则进行替换
形如:n = 1 1
n = 2 01
n = 3 1001
...
求经过n步替换之后 串中只含复数个0的连续子串(不难发现,这种子串只能是‘00’)的出现次数
因为0<n<=1000的限制 在最坏情况下(n==1000)串的长度将达到2^1000位 排除了直接模拟上述替换过程的可能
列出前几项的替换结果:
n = 0 1 ‘00’=0 ‘01’=0
n = 1 01 ‘00’=0 ‘01’=1
n = 2 1001 ‘00’=1 ‘01’=0
n = 3 01101001 ‘00’=1 ‘01’=2
n = 4 1001011001101001 ‘00’=3 ‘01’=2
n = 5 01101001100101101001011001101001 ‘00’=5 ‘01’=6
在上面的数据 不仅给出结果串 还统计出了串中‘00’对和‘01’对的个数【注:‘01’的个数是取出全部的‘00’对后才统计】
从n = 3开始 观察可以发现 01 -> 1001 即每个00对(1001)都是由01对转化而来
而每个00对(1001)又将产生一个 00对 和 两个 01对(见n=2->3)
由上述可得 n步时00对的个数 = n-1步的00对的个数 + n-1的01对的个数(即n-2步的00对的个数 * 2)
所以可以推得 f(n) = f(n - 1) + f(n - 2) * 2
如果细心的话,可以发现,当n大到一定程度时,由于上面给出的公式有着与斐波拉契数列相似的递增效应, 最终结果的数值会非常大大大大大,用__int64都远远无法满足
所以采用字符数组来模拟大数加法运算
# include <stdio.h> # include <string.h> # define MAX 1001 # define LEN 1001 char Number[MAX][LEN]; void BigNumPlus() { for(int i = 3; i < MAX; i++) { memset(Number[i], '0', LEN);//初始化 for(int j = 0; j < LEN; j++)//模拟公式 { Number[i][j] += (Number[i - 1][j] - '0') + (Number[i - 2][j] - '0') + (Number[i - 2][j] - '0'); } for(int j = 0; j < LEN; j++)//处理进位 { if(Number[i][j] > '9') { Number[i][j + 1] += (Number[i][j] - '0') / 10; Number[i][j] = (Number[i][j] - '0') % 10 + '0'; } } } } int main() { //初始值 memset(Number[1], '0', LEN); memset(Number[2], '0', LEN); Number[1][0] = '0'; Number[2][0] = '1'; BigNumPlus(); int n; while(scanf("%d",&n) != EOF) { if(n == 1)//特殊处理 { printf("0\n"); continue; } for(int i = LEN - 1; i >= 0; i--) { if(Number[n][i] != '0')//格式输出 { while(i >= 0) printf("%c",Number[n][i--]); printf("\n"); break; } } } return 0; }