[题解]P11571 「chaynOI R1 T4」橙红色的鱼

P11571 「chaynOI R1 T4」橙红色的鱼

考虑数位 DP。

下文记正在填写的数对为 \((x,y)\)

考虑到加法的进位是从低向高的,我们也从低向高进行搜索,那么需要记录的上下文信息有:

  • \(p\):当前位置。
  • \(pm\):填过的数位异或和的 \(\rm popcount\)
  • \(ps\):填过的数位和的 \(\rm popcount\)
  • \(la\):填过的数位是否满足 \(x\le y\)
  • \(lb\):填过的数位是否满足 \(y\le r\)
  • \(carry\):上一位是否向当前位进位。

搜索时直接枚举 \(x,y\) 的第 \(p\)\(i,j\),并计算出下一位的信息。

比如,\(la\to la'\) 的转移如下:

  • \(la=0\),则 \(la'=[i<j]\)
  • \(la=1\),则 \(la'=[i\le j]\)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=205,P=998244353;
string r;
int m,s,a[N],len,f[N][N][N][2][2][2];//la:是否有x<=y  lb:是否有y<=r[p]
inline int dfs(int p,int sm,int ss,int jw,int la,int lb){
	if(sm<0||ss<0) return 0;
	if(p==len+1) return (la&&lb&&!sm&&!(ss-jw));
	if(~f[p][sm][ss][jw][la][lb]) return f[p][sm][ss][jw][la][lb];
	long long ans=0;
	for(int i=0;i<2;i++) for(int j=0;j<2;j++){
		ans+=dfs(p+1,sm-(i^j),ss-(i^j^jw),(i+j+jw)>>1,la?i<=j:i<j,lb?j<=a[p]:j<a[p]);
	}
	return f[p][sm][ss][jw][la][lb]=ans%P;
}
inline int solve(){
	len=r.size();
	for(int i=0;i<len;i++) a[len-i]=r[i]-'0';
	return dfs(1,m,s,0,1,1);
}
signed main(){
	memset(f,-1,sizeof f);
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>r>>m>>s;
	cout<<solve()<<"\n";
	return 0;
}

另一种做法是从高向低进行搜索(参考 ChatSheep),那么“上一位是否进位”就不是上下文,而是需要讨论的东西了。所以我们修改 \(carry\) 的定义为“是否强制向下一位进位”。

搜索时,同样枚举 \(i,j\) 的值,并进行讨论:

  • 如果 \(carry=1\)(当前位强制向下一位进位):
    • 钦定上一位向该位置进位,前提是 \(i+j+1\ge 2\)
    • 钦定上一位不向该位置进位,前提是 \(i+j\ge 2\)
  • 如果 \(carry=0\)(当前位强制不向下一位进位):
    • 钦定上一位向该位置进位,前提是 \(i+j+1<2\)
    • 钦定上一位不向该位置进位,前提是 \(i+j<2\)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=205,P=998244353; 
string r;
int m,s,len,a[N],f[N][N][N][2][2][2];
inline int dfs(int p,int m,int s,int la,int lb,bool jw){
	if(m<0||s<0) return 0;
	if(!p) return !m&&!s&&!jw;
	if(~f[p][m][s][la][lb][jw]) return f[p][m][s][la][lb][jw];
	ll ans=0;
	for(int x=0;x<=max(a[p],la);x++){
		for(int y=0;y<=max(x,lb);y++){
			if((jw&&x+y>1)||(!jw&&x+y<2)) ans+=dfs(p-1,m-(x^y),s-(x^y),la||(x!=a[p]),lb||(x!=y),0);//前一位不进位 
			if((jw&&x+y+1>1)||(!jw&&x+y+1<2)) ans+=dfs(p-1,m-(x^y),s-(x^y^1),la||(x!=a[p]),lb||(x!=y),1);//前一位进位 
		}
	}
	return f[p][m][s][la][lb][jw]=ans%P;
}
inline int solve(){
	len=r.size();
	for(int i=0;i<len;i++) a[len-i]=r[i]-'0';
	a[++len]=0;
	return dfs(len,m,s,0,0,0);
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	memset(f,-1,sizeof f);
	cin>>r>>m>>s;
	cout<<solve()<<"\n";
	return 0;
}
posted @ 2025-11-11 14:10  Sinktank  阅读(9)  评论(0)    收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2025 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.