URAL 1057 Amount of Degrees (数位DP)

题意

求给定区间[X,Y]中满足下列条件的整数个数:这个数恰好等于K 个互不相等的B的整数次幂之和。

思路

第一道数位DP题,参考09年国家集训队论文《浅谈数位类统计问题》。 这类问题的第一步一般都先 把区间[X,Y]转化为区间[1,X]和[1,Y]。 【重要思想---数形结合、按位处理】 按照数的二进制位构建一个类似Trie树的一个二进制树,在树上进行位操作。树的每一层对应每一位。 我们先来看2进制。在这道题中,我们用f[i][j]表示高度为i含有j个1的树的个数(设叶子节点高度为0,且f[0][0] = 1),tot表示当前路径根节点上已经有的1的个数。对于一个数x,我们在它的二进制树上操作,遇到0左拐,遇到1右拐(进入右子树),并且计算它的左兄弟子树中有K-tot个1的个数,再将tot+1。如下图所示,红色为x的路径,蓝绿紫三个子树分别是三次右拐时计算的子树。 而处理大于2进制位的B进制位时,把它当作二进制位处理即可:我们先需要把每位的数值都转化为1或0。我们只需要向下找最大的符合条件的那个数,就是从左寻找第一个不是0或1的数,然后把右边的每位数字都改为1。构建好二进制数以后,按位DP即可。注意最后要是n也满足条件,也要加上去。

代码

  [cpp] #include #include #include #include #include #include #include #include #include #define MID(x,y) ((x+y)/2) #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i, begin, m) for (int i = begin; i < begin+m; i ++) using namespace std; int f[35][35]; void init(){ int n = 31; f[0][0] = 1; REP(i, 1, n){ f[i][0] = f[i-1][0]; REP(j, 1, i){ f[i][j] = f[i-1][j] + f[i-1][j-1]; } } } int change_to_bin(int x, int b){ vector v; while(x){ v.push_back(x%b); x /= b; } for (int i = (int)v.size()-1; i >= 0; i --){ if (v[i] > 1){ for (int j = i; j >= 0; j --){ v[j] = 1; } break; } } int ans = 0; for (int i = 0; i < (int)v.size(); i ++){ ans += v[i] * (1 << i); } return ans; } int cal(int x, int k){ int num = 0, tot = 0; for (int i = 30; i >= 0; i --){ if (x & (1< k) break; x = x^(1<

你可能感兴趣的:(mount)