Codeforces Round #597 (Div. 2) F Daniel and Spring Cleaning(数位DP)

题目链接:https://codeforces.com/contest/1245/problem/F

题目大意:

  l<=a<=r,l<=b<=r,问a+b=a^b的对数

题目思路:

  qsc题解视频:传送门
  这道题,就差标题后面画个括弧里面写上数位DP模板题了。。一眼数位dp,然而太久太久没写数位dp了,完全忘记了怎么写。。。。。。。。
  真的是非常简单的数位dp入门题,首先a+b=a^b等价于a&b=0,就是找到范围内a&b=0的数量。对于数位DP来说,确定0~r是比较简单的,所以通常对于l~r都是通过 s o l v e ( r ) − s o l v e ( l − 1 ) solve(r)-solve(l-1) solve(r)solve(l1)得到,但是这个题涉及两个量,这也难不倒我们!使用一个小容斥, s o l v e ( l , r ) solve(l,r) solve(l,r)表示a在0~l范围内,b在0~r范围内的情况数。那么答案就是 s o l v e ( r , r ) − 2 ∗ s o l v e ( l − 1 , r ) + s o l v e ( l − 1 , l − 1 ) solve(r,r)-2*solve(l-1,r)+solve(l-1,l-1) solve(r,r)2solve(l1,r)+solve(l1,l1),然后怎么solve呢?记忆化搜索, d f s ( l , r , p o s , a , b ) dfs(l,r,pos,a,b) dfs(l,r,pos,a,b)分别表示第一个数范围0~l,第二个数0~r,然后当前枚举到哪一位,a表示第一个数枚举的时候有没有限制(之前全都一样说明现在还是得被这一位限制,比如对于123来说,现在假如枚举12,就说明有限制,最后一位只能0~3,但是假如说枚举的是11,那么最后一位就随便来,就能是0~9)。然后就中规中矩的干活咯,看看后面的情况。不过我已经菜到忘记更新哪个变量,返回哪个变量。。唉,蓝瘦

以下是代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>

using namespace std;
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
ll dp[40][2][2];
ll dfs(int l,int r,int pos,int a,int b){
    
    
    if(pos==-1)return 1;
    if(dp[pos][a][b]!=-1)return dp[pos][a][b];
    int la=1,lb=1;
    if(a)la=(l>>pos)&1;
    if(b)lb=(r>>pos)&1;
    dp[pos][a][b]=0;
    rep(i,0,la){
    
    
        rep(j,0,lb){
    
    
            if(i&j)continue;
            dp[pos][a][b]+=dfs(l,r,pos-1,a&(i==la),b&(j==lb));
        }
    }
    return dp[pos][a][b];
}
ll solve(int l,int r){
    
    
    if(l<0)return 0;
    memset(dp,-1,sizeof(dp));
    return dfs(l,r,30,1,1);
}
int main()
{
    
    
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--){
    
    
        int l,r;
        cin>>l>>r;
        cout<<solve(r,r)-2*solve(l-1,r)+solve(l-1,l-1)<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/toohandsomeIeaseId/article/details/104151387
今日推荐