https://ac.nowcoder.com/acm/contest/9925/C
今天我们队配合问题极大。。。这道前期数位DP给数学队友在看他半天不会写,然后我这个数学辣鸡wa了一年D。。。交换一下两个题感觉能少2小时罚时。。。
这题意思就是 i,j 随便选,不超过X,Y,然后i,j二进制上不能有相同的位都是1,然后一个数字的贡献就是他二进制上的最高位的1是哪一位+1就行了
那么就是个简单数位DP,由于贡献仅与最高位有关,我们dp只要算数量就行了,然后用全局变量来计算答案
dp[k][fmx][fx][fy],k表示已经到2进制的哪一位了,注意k=1-32分别对应2^31---2^0位,然后fmx表示已经有1了没有,fx表示i是否还顶着X这个上边界,fy表示j是否还顶着Y,的方案数
那么每枚举一个k,我们可以安排i,j这一位都是0,i=1 j=0或者i=0 j=1这样3种情况,由于我们答案只与最高位有关,那么当fmx==1 且当前有一位为1的时候,加入总答案,ans+=tmp*(33-k)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll x,y;ll ans;
int xa[35],ya[35];
ll dp[35][2][2][2];
inline void prework()
{
scanf("%lld%lld",&x,&y);
for(int i=31;i>=0;i--)
xa[31-i+1]=(x>>i)&1;
for(int i=31;i>=0;i--)
ya[31-i+1]=(y>>i)&1;
}
inline ll dfs(int k,bool fmx,bool fx,bool fy)
{
if(k>32)
return 1;
if(dp[k][fmx][fx][fy]>=0)
return dp[k][fmx][fx][fy];
ll ret=0,tmp;
int upx=(!fx || xa[k]),upy=(!fy || ya[k]);
(ret+=dfs(k+1,fmx,fx&&xa[k]==0,fy&&ya[k]==0))%=mod;
if(upx>=1)
{
tmp=dfs(k+1,0,fx&&xa[k]==1,fy&&ya[k]==0);
ret=(ret+tmp)%mod;
if(fmx)
(ans+=(33-k)*tmp%mod)%=mod;
}
if(upy>=1)
{
tmp=dfs(k+1,0,fx&&xa[k]==0,fy&&ya[k]==1);
ret=(ret+tmp)%mod;
if(fmx)
(ans+=(33-k)*tmp%mod)%=mod;
}
dp[k][fmx][fx][fy]=ret;
return ret;
}
inline void mainwork()
{
memset(dp,-1,sizeof(dp));ans=0;
dfs(1,1,1,1);
}
inline void print()
{
printf("%lld\n",ans);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
prework();
mainwork();
print();
}
return 0;
}