题目来源:
HihoCoder1318
题目要求:
如果一个二进制数包含连续的两个1,我们就称这个二进制数是非法的。小Hi想知道在所有 n 位二进制数(一共有2^n个)中,非法二进制数有多少个。例如对于 n = 3,有 011, 110, 111 三个非法二进制数。
由于结果可能很大,你只需要输出模10^9+7的余数。
解答:
本题是典型的动态规划的题目,对于i位二进制下的非法二进制数的个数,我们通过i-1位二进制数下的情况来进行求解。具体方法是:定义valid[0][i]表示i位二进制数下,并且最后一位为0的合法二进制数的个数;valid[1][i]表示i位二进制数下,最后一位是1的合法二进制数的个数;同时定义invalid[i]为i位二进制数中的非法二进制数的个数。根据题目要求,当二进制数中存在两个连续的1时为非法二进制数。因此,在计算i位二进制数中的非法二进制数时,考虑如下3种情况:
(1) 对于i-1位二进制数中最后一位是1的合法二进制数,再其后再增加一个1,就会成为一个i为的非法二进制数,根据上文中的定义,此情况的非法二进制数的数目是:valid[1][i-1]。
(2) 对于i-1位二进制数中最后一位是0的合法二进制数,再其后无论添加0或者1,都不会产生非法的二进制数。
(3) 对于i-1位二进制数中的所有非法二进制数,在其后添加0或1,得到的都是i位长度的非法二进制数,此情况的非法二进制数的数目是:2 * invalid[i-1]。
分析以上三种情况,可以得到invaid[i]的递推公式:
invalid[i] = valid[1][i-1] + 2 * invalid[i-1]
对于合法二进制数的数目,也可以用类似的分析方法。显然,一个i位的合法二进制数删去最后一位后,得到的一定是一个i-1为的合法二进制数。因此,对于i位长度最后一位是1的合法二进制数,删去末尾的1后,是一个i-1位的合法二进制数,并且,该二进制数最后一位一定是0,因为如果是1,再添加1就会有两个连续的1,而构成非法二进制数。所以:
valid[1][i] = valid[0][i-1]
而对于i位长度最后一位是0的合法二进制数,则无此限制,去掉末尾的0后,只要能保证剩余的数字是合法二进制数即可,因此:
valid[0][i] = valid[0][i-1] + valid[1][i-1]
得到递推公式后,我们还需要一个递推的起点,这个起点是显而易见的,对于1位二进制数,最后一位为0和1的合法二进制数各有一个,不存在非法二进制数,因此:
valid[0][1] = 1 valid[1][1] = 1 invalid[1] = 0
对于更一般的情况,代入递推公式计算即可。
以上为本题解法,对于输入数据n,计算invalid[n]就是本题的答案。
输入输出格式:
输入:
一个整数n(1≤n≤100)。
输出:
n位非法二进制数的数目模109+7的余数。
程序代码:
package hihocoder;
import java.util.Scanner;
/**
* This is the ACM problem solving program for hihoCoder 1318.
*
* @version 2017-04-29
* @author Zhang Yufei.
*/
public class HihoCoder1318 {
/**
* Mod Constant.
*/
private static final int MOD = 1000000007;
/**
* Used for dp.
*/
private static int[][] dp;
/**
* Used for dp.
*/
private static int[] dp2;
/**
* Input data;
*/
private static int n;
/**
* The main program.
*
* @param args
* The Command line parameters list.
*/
public static void main(String[] args) {
dp = new int[101][2];
dp2 = new int[101];
dp[1][0] = 1;
dp[1][1] = 1;
for(int i = 2; i <= 100; i++) {
long data = (long) dp[i - 1][0] + dp[i - 1][1];
data %= MOD;
dp[i][0] = (int) data;
dp[i][1] = dp[i - 1][0];
}
dp2[1] = 0;
for(int i = 2; i <= 100; i++) {
long data = (long) dp2[i - 1] * 2 + dp[i - 1][1];
data %= MOD;
dp2[i] = (int) data;
}
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
scan.close();
System.out.println(dp2[n]);
}
}