2020ICPC上海 C-Sum of Log 数位DP

2020ICPC上海 C-Sum of Log

题意

给定两个非负整数\(X,Y\),求

\[\sum_{i=0}^{X} \sum_{j= [i=0] }^{Y} [i\&j=0] \lfloor log_2(i+j)+1 \rfloor \]

\(X,Y\le 10^9,T\le 10^5\)

分析

\(dp[pos][sta][limit1][limit2]\)表示从第\(pos\)位枚举到最低位\(i\&j=0\)的状态数,\(sta\)表示第\(pos\)位之前是否有一位为\(1\)\(limit1\)\(limit2\)表示枚举到第\(pos\)位两个数是否有限制,当\(sta\)\(0\)\(pos\)这一位为1时,说明最高位就是\(pos\),将答案加上\(pos\)乘上后继状态数即可。

Code

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int T,x,y,a[31],b[31];
int dp[31][2][2][2],ans;
int add(int x,int y){
    x+=y;
    if(x>=mod) x-=mod;
    return x;
}
int mul(int x,int y){
    x=1ll*x*y%mod;
    return x;
}
int dfs(int pos,int sta,int l1,int l2){
    if(pos==-1) return 1;
    if(~dp[pos][sta][l1][l2]) return dp[pos][sta][l1][l2];
    int up1=l1?a[pos]:1;
    int up2=l2?b[pos]:1;
    int tmp=0;
    for(int i=0;i<=up1;i++){
        for(int j=0;j<=up2;j++){
            if(i&j) continue;
            if(i==j){
                tmp=add(tmp,dfs(pos-1,sta,l1&&i==a[pos],l2&&j==b[pos]));
            }else{
                int res=dfs(pos-1,1,l1&&i==a[pos],l2&&j==b[pos]);
                if(!sta) ans=add(ans,mul(res,pos+1));
                tmp=add(tmp,res);
            }
        }
    }
    return dp[pos][sta][l1][l2]=tmp;
}
void solve(int x,int y){
    int l1=0,l2=0;
    memset(a,0,sizeof a);
    memset(b,0,sizeof b);
    while(x){
        a[l1++]=x&1;
        x>>=1;
    }
    while(y){
        b[l2++]=y&1;
        y>>=1;
    }
    dfs(max(l1,l2)-1,0,1,1);
}
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&x,&y);
        memset(dp,-1,sizeof dp);
        ans=0;
        solve(x,y);
        printf("%d\n",ans);
    }
    return 0;
}
posted @ 2020-12-15 14:44  xyq0220  阅读(303)  评论(0编辑  收藏  举报