poj 3252 Round Numbers 数位dp
题目链接:
http://poj.org/problem?id=3252
题意:
求一段区间中二进制中0的数量要不能少于1的数量的数的个数。
思路:
套路 都是套路
http://blog.csdn.net/wust_zzwh/article/details/52100392
dp[pos][num],到当前数位pos,0的数量减去1的数量为num的方案数,一个简单的问题,中间某个pos位上num可能为负数(这不一定是非法的,因为我还没枚举完嘛,只要最终的num>=0才能判合法,中途某个pos就不一定了),这里比较好处理,Hash嘛,最小就-32吧(好像),直接加上32,把32当0用。
显然我要统计0的数量,前导零是有影响的。dfs记忆化的时候要加一个变量lead代表这位是不是当前数的前导0
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 typedef long long ll; 6 #define MS(a) memset(a,0,sizeof(a)) 7 #define MP make_pair 8 #define PB push_back 9 const int INF = 0x3f3f3f3f; 10 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; 11 inline ll read(){ 12 ll x=0,f=1;char ch=getchar(); 13 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 14 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 15 return x*f; 16 } 17 ////////////////////////////////////////////////////////////////////////// 18 const int maxn = 1e5+10; 19 20 int l,r,dp[50][maxn],a[50]; 21 22 int dfs(int pos,int sta,int lead,int limit){ 23 if(pos == -1) return sta>=32; 24 if(!lead && !limit && dp[pos][sta]!=-1) return dp[pos][sta]; 25 26 int up = limit ? a[pos] : 1; 27 int re = 0; 28 for(int i=0; i<=up; i++){ 29 if(lead && i==0) re += dfs(pos-1,sta,lead,limit&&i==a[pos]); 30 else re += dfs(pos-1,sta+((i==0)?1:-1),lead&&i==0,limit&&i==a[pos]); 31 } 32 if(!lead && !limit) dp[pos][sta] = re; 33 return re; 34 } 35 36 int solve(int x){ 37 int pos = 0; 38 while(x){ 39 a[pos++] = x%2; 40 x /= 2; 41 } 42 int re = dfs(pos-1,32,true,true); 43 return re; 44 } 45 46 int main(){ 47 memset(dp,-1,sizeof(dp)); 48 cin >> l >> r; 49 int ans = solve(r) - solve(l-1); 50 51 cout << ans << endl; 52 53 return 0; 54 }