这题说的是给了一个二进制数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; }
时间: 2024-10-18 00:49:19