首页 > 代码库 > http://codeforces.com/contest/776/problem/G

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;
}
View Code

 

http://codeforces.com/contest/776/problem/G