我是靠谱客的博主 专一电话,最近开发中收集的这篇文章主要介绍2020ICPC上海 C.Sum of Log(数位DP),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

在这里插入图片描述
思路:
思路很快就出来了,但是实现过程还是有点细节,一直在T。。。

可以观察发现,题中式子的结果就是 i ∣ j i|j ij的最高位。那么我们按照X,Y的二进制位跑数位DP就好了。

我初始的状态定义是 d p [ l e n ] [ h i g h ] dp[len][high] dp[len][high],代表两个数枚举到了第 l e n len len位,最高位为 h i g h high high时候的结果。但是这样定义状态有个问题,由于 l i m i t limit limit的存在,就是很多状态无法记录不下来,比如X=1000000000,Y=1的时候,前面部分几乎就是在枚举X本身。这样肯定会T。过了40%的数据。

然后又想着将 l i m i t limit limit作为状态,每次都情况 d p dp dp数组,这样就变成了 d p [ l e n ] [ h i g h ] [ l i m i t 1 ] [ l i m i t 2 ] dp[len][high][limit1][limit2] dp[len][high][limit1][limit2]。算起来的话一共有 30 ∗ 30 ∗ 2 ∗ 2 30*30*2*2 303022个状态,每个状态最坏算 3 3 3次,一共 1 e 5 1e5 1e5次询问,复杂度还是感人。过了66.67%数据。

最后查了下别人的解法,发现他们省掉了 h i g h high high这一维状态,大悟。因为最高位只可能出现在一个数字上面,所以我们枚举最高位的位置以及是出现在 X X X中还是在 Y Y Y中,复杂度就少了很大一个档次。

所以最终状态定义为 d p [ l e n ] [ l l i m i t 1 ] [ l i m i t 2 ] dp[len][llimit1][limit2] dp[len][llimit1][limit2],转移的话就是使得这个位置上 i & j ≠ 1 i& j≠1 i&j=1

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 7;
const int mod = 1e9 + 7;
typedef long long ll;

ll dp[32][2][2]; //X的位,Y的位,X|Y的最高位
int a[32],b[32];
ll dfs(int len,int limit1,int limit2) {
    if(len == -1) {
        return 1;
    }
    if(dp[len][limit1][limit2] != -1) return dp[len][limit1][limit2];
    int ans = 0;
    int up1 = limit1 ? a[len] : 1;
    int up2 = limit2 ? b[len] : 1;
    for(int i = 0;i <= up1;i++) {
        for(int j = 0;j <= up2;j++) {
            if((i & j) == 1) continue;
            ans += dfs(len - 1,limit1 && i == up1,limit2 && j == up2);
            ans %= mod;
        }
    }
    return dp[len][limit1][limit2] = ans;
}

ll solve(int X,int Y) {
    memset(dp,-1,sizeof(dp));
    int lena = -1,lenb = -1;
    for(int i = 30;i >= 0;i--) {
        a[i] = (X >> i) & 1;
        b[i] = (Y >> i) & 1;
        if(lena == -1 && a[i]) {
            lena = i;
        }
        if(lenb == -1 && b[i]) {
            lenb = i;
        }
    }
    ll res = 0;
    //X是最高位
    for(int i = lena;i >= 0;i--) {
        res += dfs(i - 1,i == lena,i > lenb) * (i + 1) % mod;
        res %= mod;
    }
    //Y是最高位
    for(int i = lenb;i >= 0;i--) {
        res += dfs(i - 1,i > lena,i == lenb) * (i + 1) % mod;
        res %= mod;
    }
    return res;
}

int main() {
    int T;scanf("%d",&T);
    while(T--) {
        int X,Y;scanf("%d%d",&X,&Y);
        ll ans = solve(X,Y);
        ans = (ans + mod) % mod;
        printf("%lldn",ans);
    }
    return 0;
}

超时代码(没有省掉最高位那个维度)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 7;
const int mod = 1e9 + 7;
typedef long long ll;

int dp[31][31][2][2]; //X的位,Y的位,X|Y的最高位
int a[32],b[32];
int dfs(int len,int high,int limit1,int limit2) {
    if(len == -1) {
        return high + 1;
    }
    if(dp[len][high][limit1][limit2] != -1) return dp[len][high][limit1][limit2];
    int ans = 0;
    int up1 = limit1 ? a[len] : 1;
    int up2 = limit2 ? b[len] : 1;
    for(int i = 0;i <= up1;i++) {
        for(int j = 0;j <= up2;j++) {
            if((i & j) == 1) continue;
            int now = high;
            if(now == 0 && ((i | j) == 1)) {
                now = len;
            }
            ans += dfs(len - 1,now,limit1 && i == up1,limit2 && j == up2);
            ans %= mod;
        }
    }
    return dp[len][high][limit1][limit2] = ans;
}

int solve(int X,int Y) {
    memset(dp,-1,sizeof(dp));
    int len = 0;
    for(int i = 30;i >= 0;i--) {
        a[i] = (X >> i) & 1;
        b[i] = (Y >> i) & 1;
        if(!len && (a[i] || b[i])) {
            len = i;
        }
    }
    return dfs(len,0,true,true);
}

int main() {
    int T;scanf("%d",&T);
    memset(dp,-1,sizeof(dp));
    while(T--) {
        int X,Y;scanf("%d%d",&X,&Y);
        int ans = solve(X,Y) - 1;
        ans = (ans + mod) % mod;
        printf("%dn",ans);
    }
    return 0;
}

最后

以上就是专一电话为你收集整理的2020ICPC上海 C.Sum of Log(数位DP)的全部内容,希望文章能够帮你解决2020ICPC上海 C.Sum of Log(数位DP)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(30)

评论列表共有 0 条评论

立即
投稿
返回
顶部