2020上海ICPC现场赛 C Sum of Log

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

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/111334994
今日推荐