[题解]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;
}
浙公网安备 33010602011771号