Comet OJ - Contest #12 XOR Pair 数位DP维护绝对值小于某个数

如果不考虑|x-y|<=m  就是一道经典数位dp题。

我们当然可以直接维护  x-y 的值,最后判断,但这样空间非常大,完全开不下。

所以我们要对这个式子进行一些变化:

|x-y|<=m
y - x >= -m ,x - y <= m
y + m - x >= 0 ;  x + m - y >= 0;

由于x,y,m每一位都只能取1,0

所以每一位的取值范围:[-1,2];

而如果上一位的取值大于等于1,或小于等于-2,则后面的值不会影响前面。

若上一位取值为-1,当前位为2,则会抵消上一位的影响。

所以我们只需要维护截至目前为止,前面y + m - x  ,x+ m - y 的值即可。

若为1,或-2则认为无法改变。

具体细节见代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define re register
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;
/*
int head[M],cnt=1;
void init(int n){cnt=1;for(int i=0;i<=n;i++)head[i]=0;}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
ll dp[66][4][4][2][2];
int da[66],db[66],dn[66],dm[66],na,nb,nn,nm;
ll dfs(int len,int val1,int val2,bool la,bool lb)
{
	//cout<< len <<" "<<val1<<"  "<<val2<<" "<<la<<"  "<<lb<<endl;
	val1 = min(val1,1),val2 = min(val2,1);//大于等于1,后面无论取什么都无法改变前面一位的1 
	if(val1 < -1 || val2 < -1)return 0;
	if(len <= 0)return val1 >= 0 && val2 >= 0;
	if(~dp[len][val1 + 1][val2 + 1][la][lb])return dp[len][val1 + 1][val2 + 1][la][lb];
	ll ans = 0;
	int upx = la ? da[len] : 1;
	int upy = lb ? db[len] : 1;
	for(int i = 0;i <= upx;i++)
		for(int j = 0;j <= upy;j++)
		{
			if(i ^ j == dn[len])
			{
				int tp1 = i + dm[len] - j;
				int tp2 = j + dm[len] - i;
			//	cout<<"===========   "<<len<<"  "<<i <<" - "<<j<<"     "<<tp1<<"  "<<tp2<<" - - --  "<<dm[len]<<endl;
				ans += dfs(len-1,val1 * 2 + tp1,val2 * 2 + tp2,la && i == upx,lb && j == upy);
			}
		} 
	dp[len][val1 + 1][val2 + 1][la][lb] = ans;
	return ans; 
}
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int T ;
  	cin>>T;
  	while(T--)
  	{
  		ll a,b,n,m;
  		cin>>a>>b>>n>>m;
  		/*
	  		|x-y|<=m
	  		y - x >= -m ,x - y <= m
	  		y + m - x >= 0 ;  x + m - y >= 0;
	  		-11, -1, 0, 12
	  		0,    1, 2, 3
  		*/
  		//初始化不要忘记 
  		memset(da,0,sizeof(da));
  		memset(db,0,sizeof(db));
  		memset(dn,0,sizeof(dn));
  		memset(dm,0,sizeof(dm));
  		na=nb=nm=nn=0;
  		while(a)da[++na]=a%2,a/=2;
  		while(b)db[++nb]=b%2,b/=2;
  		while(n)dn[++nn]=n%2,n/=2;
  		while(m)dm[++nm]=m%2,m/=2;
  		int mx=max(max(na,nb),max(nn,nm));
  		memset(dp,-1,sizeof(dp));
  		cout<<dfs(mx,0,0,true,true)<<endl;;
	}
	return 0;
}	
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值