首页 > 代码库 > hdu5106 数位dp
hdu5106 数位dp
这题说的是给了一个二进制数R , 计算出 在[0,R) 区间内的数, 二进制中有n个1 个和
n<=1000; R<2^1000, 这样 用dp[len][lee] 表示在第len位的时候已经放了lee个1 个总和, num[len][lee] 表示在第len位的时候已经放了lee个1 个数有多少个,这样只要考虑当前位置放1与不放1 记忆化进行搜索
#include <iostream>#include <algorithm>#include <cstdio>#include <string.h>using namespace std;const int maxn =1005;typedef long long ll;const ll mod=1000000007;ll dp[maxn][maxn];ll num[maxn][maxn];char str[maxn];ll dig[maxn];void dfs(int loc, int lee , bool e, ll &value, ll &ge){ value = ge = 0; if(e==false&& num[loc][lee]!=-1 ){ value=dp[loc][lee]; ge =num[loc][lee]; return ; } if(loc==0&&lee==0){ value=0, ge=1; return ; } int we = e? str[loc-1]-‘0‘:1; ll ans=0, nu=0; if(we==1){ if(loc-1>=lee){ dfs(loc-1,lee,false,ans,nu); value=ans, ge=nu; } if( lee > 0 ){ dfs(loc-1,lee-1,e,ans, nu); value=( value + ans + ( dig[loc-1] )*nu%mod )%mod; ge = ( nu + ge )%mod; } }else{ if(loc-1>=lee){ dfs(loc-1,lee,e,ans,nu); value= ans; ge=nu; } } if(e==false) { dp[loc][lee] = value, num[loc][lee]=ge; }}int main(){ int n; dig[0]=1; for(int i=1; i<=1000; ++i) dig[i]=(dig[i-1]*2)%mod; while(scanf("%d%s",&n,str)==2){ int len = strlen(str); for(int i=0; i<len/2; ++i){ char c = str[i]; str[i]=str[len-1-i]; str[len-1-i]=c; } memset(dp,0,sizeof(dp)); memset(num,-1, sizeof(num)); memset(num[0],0,sizeof(num[0])); num[0][0]=1; ll ans=0,nu=0; dfs( len , n , true, ans, nu); ll digt=0;nu=0; for(int i=0; i<len; ++i){ if(str[i]==‘1‘){ digt++; nu= ( nu + dig[i])%mod; } } if(digt==n) ans=(ans-nu+mod)%mod; printf("%I64d\n",ans); } return 0;}
hdu5106 数位dp
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。