HDOJ 2065 "红色病毒"问题

现在有一长度为N的字符串,满足一下条件:
(1) 字符串仅由A,B,C,D四个字母组成;
(2) A出现偶数次(也可以不出现);
(3) C出现偶数次(也可以不出现);
计算满足条件的字符串个数.
当N=2时,所有满足条件的字符串有如下6个:BB,BD,DB,DD,AA,CC.
由于这个数据肯能非常庞大,你只要给出最后两位数字即可.

Input 每组输入的第一行是一个整数T,表示测试实例的个数,下面是T行数据,每行一个整数N(1<=N<2^64),当T=0时结束.

Output 对于每个测试实例,输出字符串个数的最后两位,每组输出后跟一个空行.

因为有了A、C需要出现偶数次的要求,就出现合法和不合法的不同分组。
在不合法的组里,又有
1.A出现奇数次、C出现偶数次;
2.C出现奇数次、A出现偶数次;
3.A出现奇数次、C出现奇数次;
三种情况。这四种情况已经包含了所有可能

我们用数组
f[n][0]保存长度为n,合法的字符串的个数。
f[n][1]保存长度为n,仅A出现奇数次的字符串的个数。
f[n][2]保存长度为n,仅C出现奇数次的字符串的个数。
f[n][3]保存长度为n,A、C出现奇数次的字符串的个数。

f[n][0]
长度为n-1的合法字符串在末尾加上一个B或者D,都可以变成长度为n的合法字符串。
长度为n-1的仅A出现奇数次的字符串再在末尾加上一个A,也可以变成合法字符串。
长度为n-1的仅C出现奇数次的字符串再在末尾加上一个C,也可以变成合法字符串。
注意此时尾插已经穷尽了所有可能,所以不需要考虑插入位置。
所以,f[n][0] = 2 × f[n-1][0] + f[n-1][1] + f[n-1][2];

f[n][1]
长度为n-1的合法字符串在末尾加上A,都可以变成长度为n的仅A出现奇数次的字符串。
长度为n-1的仅A出现奇数次的字符串再在末尾加上一个B或者D,也可以变成仅A出现奇数次的字符串。
长度为n-1的A、C出现奇数次的字符串再在末尾加上一个C,也可以变成仅A出现奇数次的字符串。
所以,f[n][1] = 2 × f[n-1][1] + f[n-1][0] + f[n-1][3];

f[n][2]
长度为n-1的合法字符串在末尾加上C,都可以变成长度为n的仅C出现奇数次的字符串。
长度为n-1的仅C出现奇数次的字符串再在末尾加上一个B或者D,也可以变成仅C出现奇数次的字符串。
长度为n-1的A、C出现奇数次的字符串再在末尾加上一个A,也可以变成仅C出现奇数次的字符串。
所以,f[n][2] = 2 × f[n-1][2] + f[n-1][0] + f[n-1][3];

f[n][3]
长度为n-1的A、C出现奇数次的字符串在末尾加上一B或者D,都可以变成长度为n的A、C出现奇数次的字符串。
长度为n-1的仅A出现奇数次的字符串再在末尾加上一个C,也可以变成A、C出现奇数次的字符串。
长度为n-1的仅C出现奇数次的字符串再在末尾加上一个A,也可以变成A、C出现奇数次的字符串。
所以,f[n][3] = 2 × f[n-1][3] + f[n-1][1] + f[n-1][2];

综上所述,我们得到:
f[n][0] = 2 × f[n-1][0] + f[n-1][1] + f[n-1][2]; ①
f[n][1] = 2 × f[n-1][1] + f[n-1][0] + f[n-1][3]; ②
f[n][2] = 2 × f[n-1][2] + f[n-1][0] + f[n-1][3]; ③
f[n][3] = 2 × f[n-1][3] + f[n-1][1] + f[n-1][2]; ④

f[1][0] = 2
f[1][1] = 1
f[1][2] = 1
f[1][3] = 0

发现f[1][1]与f[1][2]初始状态相同,而且以后迭代方程也相同,所以f[n][1] = f[n][2]
又有f[n][0] + f[n][3] = f[n][1] + f[n][2]
∵f[n][0] + f[n][1] + f[n][2] + f[n][3] = 4^n
∴f[n][0] + f[n][3] = f[n][1] + f[n][2] = 2 × 4^n-1
∴f[n-1][1] + f[n-1][2] = 2 × 4^n-2
∴f[n][0] = 2 × f[n-1][0] + f[n-1][1] + f[n-1][2] = 2 × f[n-1][0] + 2 × 4^n-2

我们得到:
f[n][0] = 2 × f[n-1][0] + 2^2n-3
f[n-1][0] = 2 × f[n-2][0] + 2^2n-5

f[n-m][0] = 2 × f[n-m-1][0] + 2^2n-2m-3

f[2][0] = 2 × f[1][0] + 2^1
f[1][0] = 2

开始一层层往下迭代:
f[n][0]
= 2 × f[n-1][0] + 2^2n-3
= 2^2 × f[n-2][0] + 2^2n-4 + 2^2n-3

= 2^m × f[n-m][0] + 2^2(n-m)-1+m-1 + … + 2^2n-3
= 2^n-1 × f[1][0] + 2^n-1 + 2^n +… + 2^2n-3
f[1][0] = 2;

∴f[n][0] = 2^n + 2^n-1 + 2^n +… + 2^2n-3 = 2^2n-2 + 2^n-1

编码建议
Programing 公式得到了:f(n) = 2^2n-2 + 2^n-1
但就这样直接编程那是不可能实现的,因为n的范围1≤N<2^64
怎么的范围,是不能求出f(n)的。所以还得找其他规律。

因为题目只要求输出最后2位数,我们依次输出2的n的最后两位看看…
2^0 -> 1
2^1 -> 2
2^2 -> 4
2^3 -> 8
2^4 -> 16
2^5 -> 32
2^6 -> 64
2^7 -> 28
2^8 -> 56
2^9 -> 12
2^10 -> 24
2^11 -> 48
2^12 -> 96
2^13 -> 92
2^14 -> 84
2^15 -> 68
2^16 -> 36
2^17 -> 72
2^18 -> 44
2^19 -> 88
2^20 -> 76
2^21 -> 52
2^22 -> 4
到了222时,末尾2位又变成4,与22一样,这时候就进入了一个循环了(每20个一次循环)。
所以,结果只能是这22个中的一个。只有n=0 和 n=1是需要特殊考虑的。其他n就等于2(n-2) % 20 + 2的值了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值