CF1593F Red-Black Number(記憶化搜尋,動態規劃)
阿新 • • 發佈:2021-11-03
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'); } } }
這道題告訴我,當我們面對這種搜尋規模偏大的情況下,我們可以考慮運用記憶化搜尋 + 設定變換維度 ,來達到縮小搜尋規模的目的。當動態規劃方程不太直觀時,我們可以轉為運用記憶化搜尋,從前向後更新狀態,這樣在某些題中更為直觀自然。