CF1593F Red-Black Number(记忆化搜索,动态规划)
Red-Black Number
思路:我们发现每个格子有两种染色方式,所以一共是\(2^{40}\)种,不能通过,想到可以进行折半搜索,每次\(2^{20}\)种,然后再进行整合答案,能够通过。但有一种规模更小的搜索方法。我们设\(f(i,j,k,t)\)表示当前进行到第\(i\)个,当前被染红的格子的十进制表示\(modA\) 的值为\(j\),染黑的格子的十进制表示\(modB\)的值为\(k\),当前有\(t\)个红格子的状态是否可行。
考虑搜索,即
\(f(i,j,k,t) ->f(i+1,(j*10+s[i+1])moda,k,t+1)\)
\(f(i,j,k,t)->f(i+1,j,(k*10+s[i+1])modb,t)\)
然后统计一下答案即可。
\(Code:\)
const int N = 33+10;
char s[N];
int _;
int a,b,n;
int ans = 99999;
bool st[N][N][N][N];
//int head[N][N][N][N];
vector<int>G,Ans;
void dfs(int id,int j,int k,int t){
if(st[id][j][k][t] == 1)return;
if(id == n and j == 0 and k == 0 and t != 0 and t != n){
int now = abs(t - (n - t));
if(ans > now){
Ans.clear();Ans = G;
//for(auto i:Ans)printf("%d",i);pc('\n');
ans = now;return ;
}
}
st[id][j][k][t] = 1;
if(id == n)return ;
int num = s[id+1] - '0';
int x = (num + j * 10)%a;
int y = (num + k * 10)%b;
//head[id+1][x][k][t+1] =
G.pb(id+1);
dfs(id+1,x,k,t+1);
G.pop_back();
dfs(id+1,j,y,t);
}
bool col[N];
void solve(){
read(_);
while(_--){
ans = 99999;
memset(st,false,sizeof st);
memset(col,false,sizeof col);
G.clear();
read(n);read(a);read(b);
scanf("%s",s+1);
dfs(0,0,0,0);
//write(ans);pc('\n');
if(ans == 99999){puts("-1"); }
else {
for(auto i:Ans)col[i] = true;
for(int i=1;i<=n;++i)pc(col[i]?'R':'B');
pc('\n');
}
}
}
这道题告诉我,当我们面对这种搜索规模偏大的情况下,我们可以考虑运用记忆化搜索 + 设定变换维度 ,来达到缩小搜索规模的目的。当动态规划方程不太直观时,我们可以转为运用记忆化搜索,从前向后更新状态,这样在某些题中更为直观自然。