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