[题解]P9387 [THUPC 2023 决赛] 巧克力

P9387 [THUPC 2023 决赛] 巧克力

参考:浅谈数位 DP,从入门到入土 ChatSheep。笔记质量很高,感谢原作者。

由于还没学博弈论,所以就直接跳到转化后的题意了。

给定 \(n,m\),令 \(x=1\oplus\dots\oplus n\oplus m\)。求满足下列条件的三元组 \((a,b,c)\) 数量:

  • \(a+b+c\le n\)\(a+b+c=m\)(若都满足,算 \(2\) 次)。

  • \((a+b+c)\oplus a\oplus c=x\)

  • \(a,c\ge 0,b>0\)

考虑数位 DP。

因为出现了求和,所以需要处理进位的问题,常见的套路是从低位向高位枚举。

具体来说,在搜索过程中记录 \(f[p][carry][limn][eqm][zrob]\)

  • \(p\):当前正在填写 \(a,b,c\) 的哪一位(从最低位即第 \(0\) 位开始)。

  • \(carry=0/1/2\)\(p\)\(p+1\) 的进位数。

  • \(limn=0/1/2\)\(a+b+c\) 的低 \(p\) 位与 \(n\) 的低 \(p\) 位的大小关系(\(<,=,>\))。

  • \(eqm=0/1\)\(a+b+C\) 的低 \(p\) 位是否与 \(m\) 的低 \(p\) 位相同。

  • \(zrob=0/1\)\(b\) 的低 \(p\) 位是否为 \(0\)

转移时枚举 \(a,b,c\) 的第 \(p\) 位,在满足第二条的情况下继续搜索。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=64,P=1e9+7;
int t,n,m,x,f[N][3][3][2][2],ta[N],tb[N],tc[N];
bitset<N> a;
int dfs(int p,int carry,int limn,bool eqm,bool zrob){//limn=0/1/2 </=/>
	if(p==64) return (!carry&&!zrob)*(eqm+(limn<=1));
	if(~f[p][carry][limn][eqm][zrob]) return f[p][carry][limn][eqm][zrob];
	int ans=0;
	bool ndig=(n>>p)&1,mdig=(m>>p)&1,xdig=(x>>p)&1;
	for(int a=0;a<2;a++) for(int b=0;b<2;b++) for(int c=0;c<2;c++){
		bool d=(a+b+c+carry)&1;
		ta[p]=a,tb[p]=b,tc[p]=c;
		if((d^a^c)==xdig) ans+=dfs(p+1,(a+b+c+carry)>>1,d<ndig?0:d==ndig?limn:2,eqm&&d==mdig,zrob&&!b);
	}
	return f[p][carry][limn][eqm][zrob]=ans%P;
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>t;
	while(t--){
		cin>>n>>m;
		x=m^((n&3)==0?n:(n&3)==1?1:(n&3)==2?n+1:0); 
		memset(f,-1,sizeof f);
		cout<<dfs(0,0,!n,1,1)<<"\n";
	}
	return 0;
}
posted @ 2025-11-10 19:49  Sinktank  阅读(8)  评论(0)    收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2025 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.