http://codeforces.com/contest/776/problem/G
题意: 讲一个16进制的数字num的每一位拆分下来 也就是sum = $\sigma(2 ^ a_i)$ 每一个a_i 都是不同的
举个栗子: $1014_16$ 就是 $2^1 + 2 ^ 0 + 2 ^ 4$
求得的sum是个十进制的数字 然后将sum和num都化为二进制进行异或,如果异或后的值小于num那么++ans
现在题目是给出一个区间[l, r] 问这个区间内有多少个满足条件的数,也就是区间内ans的大小
思路:
贪心+数位dp, 定义三个状态 dp[mask1][mask2][len]
mask1代表的是枚举二进制上的1,说的更清楚点就是 $2^mask1$ 枚举每个二进制位的1 mask1不会超过16的因为$\sigma_{i = 0}^{15}{2^i} = 2^16-1$;
mask2代表的是不超过16位数字(2进制下)的十进制数 因为题目是给出了数据范围的限制的, 所以 mask[i] = mask[i]%65536
len 表示的是数字的长度同样也就是枚举最后的16位
状态转移是 dp[mask1][mask2][len] += $\sigma_{i = 0}^{15}dp[max(mask1, i)][mask2*16 + i][len-1]$
然后dfs进行记忆化搜索就可以了,这里不得不感叹一下,cf的评测机真心快。 我本地跑了好几秒,而题目的时限是2.5s 然而不影响AC
最后上代码:
#include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> #include <map> #include <set> #include <vector> #include <stdlib.h> #include <math.h> #include <string> #include <stack> #include <queue> using namespace std; long long dp[16][65537][17]; int position[1100005]; int bit[200000]; bool flag = false; long long max(long long a, long long b) { return (a > b ? a : b); } long long dfs(long m, long long p, long long pos) { // cout << m << ends << p << ends << pos << endl; if (dp[m][p][pos] != -1) { return dp[m][p][pos]; } if (pos == 0) { //return (dp[m][p][pos] = !!((1 << m) & p)); if ((1 << m)&p) dp[m][p][pos] = 1; else dp[m][p][pos] = 0; return dp[m][p][pos]; } dp[m][p][pos] = 0; for (int i = 0; i < 16; ++i) dp[m][p][pos] += dfs(max(m, i), position[p*16+i], pos-1); return dp[m][p][pos]; } long long calc(string s) { int len = s.length(); long long sum = 0ll; for (int i = 0; i < len; ++i) { sum *= 16; if (s[i] >= '0' && s[i] <= '9') sum += s[i] - '0'; else sum += s[i] - 'a' + 10; } if (flag) --sum; for (int i = 0; i < len; ++i) { bit[i] = sum % 16; sum /= 16; } long long ans = 0; int m = 0, p = 0; for (int i = len - 1; i >= 0; --i) { for (int j = 0; j < bit[i]; ++j) { ans += dp[max(m, j)][position[p*16 + j]][i]; } m = max(m, bit[i]); p = position[p * 16 + bit[i]]; } ans += dp[m][p][0]; return ans; } void solveG() { int q; cin >> q; while (q-->0) { flag = false; string left; cin >> left; string right; cin >> right; long long ans = calc(right); flag = true; ans -= calc(left); cout << ans << endl; } } int main() { ios::sync_with_stdio(false); memset(dp, -1, sizeof dp); position[0] = 0; for (int i = 1; i <= 1100005; ++i) { position[i] = position[i - 1] + 1; if (position[i] == 65536) position[i] = 0; } dfs(0, 0, 16); solveG(); return 0; }