hihoCoder1318—非法二进制数(数位dp)

题目链接:传送门

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB

描述

如果一个二进制数包含连续的两个1,我们就称这个二进制数是非法的。

小Hi想知道在所有 n 位二进制数(一共有2n个)中,非法二进制数有多少个。

例如对于 n = 3,有 011, 110, 111 三个非法二进制数。

由于结果可能很大,你只需要输出模109+7的余数。

输入

一个整数 n (1 ≤ n ≤ 100)。

输出

n 位非法二进制数的数目模109+7的余数。

样例输入
3
样例输出
3

解题思路:用数位dp求出合法的二进制数个数num,然后2^n-num

dp[pos][state]:state记录二进制数的前一位是否为1。


#include <cstdio>  
#include <cstring>  
#include <cmath>  
#include <iostream>  
#include <queue>
#include <set>
#include <string>
#include <stack>
#include <algorithm>
#include <map>
#include <bitset>
using namespace std;  
typedef long long ll;
const int N = 105;
const int M = 1000009;
const int INF = 0x3fffffff;
const int mod = 1e9+7;
const double Pi = acos(-1.0);
const double sm = 1e-9;
typedef pair<int,int>PA;

int a[N],dp[N][2],re[N];

void getRe()
{
	re[0] = 1;
	for( int i = 1 ; i < N ; ++i ){
		re[i] = re[i-1]*2%mod;
	}
}

int dfs( int pos , int state , int flag , int limit )
{
	if( pos == -1 ) return flag == 0;
	if( dp[pos][state] != -1 && !limit ) return dp[pos][state];

	int up = (limit==0)?1:a[pos];
	int ans = 0;

	for( int i = 0 ; i <= up ; ++i ){
		if( flag || (i==1&&state) ) continue;
		ans = (ans+dfs( pos-1 , i == 1 , flag||(i==1&&state) , limit&&(i==a[pos]))%mod)%mod;
	}

	if( !limit ) dp[pos][state] = ans;
	return ans;
}

int solve( int n )
{
	for( int i = 0 ; i < n ; ++i ) a[i] = 1;
	return dfs( n-1 , 0 ,  0 , 1 );
}

int main()
{
	int n;
	getRe();
	memset( dp , -1 , sizeof(dp) );
	while( cin >> n ){
		int ans = solve(n);
		ans = re[n]-ans;
		if( ans < 0 ) ans += mod;
		cout << ans << endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值