LightOJ 1032 Fast Bit Calculations(数位DP)
2015-11-23 21:05
288 查看
题意:给一个n,问从0~n的所有数,二进制包含的"11"一共有多少个。
思路:dp[i][j]维护长度为i,以j开头(0<=j<=1),包含的"11"有多少。那么有转移方程:
dp[i][0] = dp[i-1][0] + dp[i-1][1];
dp[i][1] = dp[i][0] + (1 << (i - 2));
j == 0时,显然,直接从dp[i-1]为多少dp[i][0]就有多少。j==1时,除了包含dp[i-1]的情况,还要考虑,当digit[i-1]也为1时,此时digit[i]与digit[i-1]组成一个"11",那么显然要加上(1 << (i - 2))。即以digit[i] digit[i-1]开头的数有这么多个。
算答案时,对于一个n,如果对应位为1,即(1 << i) & n == 1,此时长度为i + 1,首先它一定包含了比(1 << i)小的情况,即dp[i+1][0]。由于我们是从数的高位向低位算的,我们定义一个cnt表示到这位之前已经出现的"11"对数。那么显然又需加上cnt * (1 << i)。同时考虑此位是否与上一位组成一个"11",如果是,则cnt ++。
需要注意我们每次加和的都是数到当前位时比它小的情况,也就是说,我们没有考虑n本身。因此最后加上cnt,即n包含的“11”个数。
下面考虑用记忆化搜索的方式。
我们dp[i][j]表示的意义不变。思路和之前的差不多,扔是从高位往低位推。flag表示每一位到没到头。没有到头的话仍是加上(1 << (i - 2)),否则要算一下。
思路:dp[i][j]维护长度为i,以j开头(0<=j<=1),包含的"11"有多少。那么有转移方程:
dp[i][0] = dp[i-1][0] + dp[i-1][1];
dp[i][1] = dp[i][0] + (1 << (i - 2));
j == 0时,显然,直接从dp[i-1]为多少dp[i][0]就有多少。j==1时,除了包含dp[i-1]的情况,还要考虑,当digit[i-1]也为1时,此时digit[i]与digit[i-1]组成一个"11",那么显然要加上(1 << (i - 2))。即以digit[i] digit[i-1]开头的数有这么多个。
算答案时,对于一个n,如果对应位为1,即(1 << i) & n == 1,此时长度为i + 1,首先它一定包含了比(1 << i)小的情况,即dp[i+1][0]。由于我们是从数的高位向低位算的,我们定义一个cnt表示到这位之前已经出现的"11"对数。那么显然又需加上cnt * (1 << i)。同时考虑此位是否与上一位组成一个"11",如果是,则cnt ++。
需要注意我们每次加和的都是数到当前位时比它小的情况,也就是说,我们没有考虑n本身。因此最后加上cnt,即n包含的“11”个数。
#include <algorithm> #include <iostream> #include <sstream> #include <cstring> #include <cstdio> #include <vector> #include <string> #include <queue> #include <stack> #include <cmath> #include <set> #include <map> using namespace std; typedef long long LL; #define mem(a, n) memset(a, n, sizeof(a)) #define ALL(v) v.begin(), v.end() #define si(a) scanf("%d", &a) #define sii(a, b) scanf("%d%d", &a, &b) #define siii(a, b, c) scanf("%d%d%d", &a, &b, &c) #define pb push_back #define eps 1e-8 const int inf = 0x3f3f3f3f, N = 50 + 5, MOD = 1e9 + 7; int T, cas = 0; int n, m; LL dp [2]; void init() { for(int i = 2; i < 32; i ++) { dp[i][0] = dp[i-1][0] + dp[i-1][1]; dp[i][1] = dp[i][0] + (1 << (i - 2)); } } int main(){ #ifdef LOCAL freopen("/Users/apple/input.txt", "r", stdin); // freopen("/Users/apple/out.txt", "w", stdout); #endif init(); si(T); while(T --) { si(n); LL ans = 0, cnt = 0; for(int i = 31; i >= 0; i --) { if(n & (1 << i)) { ans += dp[i+1][0] + cnt * (1 << i); if((1 << (i + 1)) & n) cnt ++; } } ans += cnt; printf("Case %d: %lld\n", ++ cas, ans); } return 0; }
下面考虑用记忆化搜索的方式。
我们dp[i][j]表示的意义不变。思路和之前的差不多,扔是从高位往低位推。flag表示每一位到没到头。没有到头的话仍是加上(1 << (i - 2)),否则要算一下。
#include <algorithm> #include <iostream> #include <sstream> #include <cstring> #include <cstdio> #include <vector> #include <string> #include <queue> #include <stack> #include <cmath> #include <set> #include <map> using namespace std; typedef long long LL; #define mem(a, n) memset(a, n, sizeof(a)) #define ALL(v) v.begin(), v.end() #define si(a) scanf("%d", &a) #define sii(a, b) scanf("%d%d", &a, &b) #define siii(a, b, c) scanf("%d%d%d", &a, &b, &c) #define pb push_back #define eps 1e-8 const int inf = 0x3f3f3f3f, N = 50 + 5, MOD = 1e9 + 7; int T, cas = 0; int n, m; LL dp [2], digit , num; LL dfs(int i, int k, bool flag) { if(i == 1) return 0; LL& ret = dp[i][k], tmp = 0; if(!flag && ~ret) return ret; int ed = flag ? digit[i-1] : 1; for(int j = 0; j <= ed; j ++) { bool ok = (flag && j == ed); tmp += dfs(i - 1, j, ok); if(j == 1 && k == 1) { if(ok) tmp += num % (1 << (i - 2)) + 1; else tmp += (1 << (i - 2)); } } if(!flag) ret = tmp; return tmp; } LL cal(LL x) { int len = 0; num = x; while(x) { digit[++ len] = x & 1; x >>= 1; } return dfs(len + 1, 0, 1); } int main(){ #ifdef LOCAL freopen("/Users/apple/input.txt", "r", stdin); // freopen("/Users/apple/out.txt", "w", stdout); #endif mem(dp, -1); si(T); while(T --) { si(n); printf("Case %d: %lld\n", ++ cas, cal((LL)n)); } return 0; }
相关文章推荐
- 为什么要乘以unity_Scale.w?
- Android实战技巧之九:最新Android开发环境(Eclipse+ADT+Android 5.0)
- 黑马程序员——Java笔记——接口
- 求n^k的前缀和
- HDU 1874 畅通工程续
- Git -- 不错的指导
- spring项目中dubbo相关的配置文件出现红叉的问题
- topcoder13185 TreePuzzle
- 如何压缩虚拟机文件
- mapreduce Wordcount输入文件在hdfs上的实例
- ViewPager+Indicator(如何写indicator)
- 内存管理:内存泄漏和空悬指针
- FC400A与400B的区别
- ViewPager 详解(一)---基本入门
- MATLAB的cat()函数
- Android自定义控件之仿京东商城下拉刷新
- 用Maven构建项目&写一个简单的Mapper-Reducer
- 善於偽善
- Install Multi Neo4J-server on Single Server
- 学习之路/免费的图库推荐