[Codeforces Round #748 (Div. 3)](https://codeforces.com/contest/1593) F. Red-Black Number 記憶化搜尋
阿新 • • 發佈:2021-10-17
題意
給出\(n\)位的十進位制數和數字\(A,B\),要求把給出的十進位制數的每一位染上黑色或紅色,使得紅色部分按順序組成的十進位制數(可能有前導0)以及黑色部分按順序組成的十進位制數(可能有前導0)能分別被\(A,B\)整除,並且紅色的位數和黑色的位數差的絕對值最小。
\(2\le n \le 40,1\le A,B\le 40\),無解輸出-1
題解
注意到\(A,B\)都很小,考慮從\(A,B\)入手
可以用類似快讀的寫法,中間加個取模就能動態維護當前選出的數字組成的數能否被整除。 把取模後的結果加入到狀態中,則能夠得到一個四維的狀態(cur, x, y, cnt),表示當前在處理從高到低第cur位,黑色的數字組成的數取模後為x, 紅色的數字組成的數取模後為y,選了cnt個黑色數字。
每一個狀態只需要訪問一次,那麼就得到了時空複雜度均為\(O(n^4)\)的演算法。
#include<bits/stdc++.h> using namespace std; const int maxn = 40 + 7; #define ll long long int n, m, k, tot, ans, A, B; char s[maxn], aa[maxn], fa[maxn]; int rd() { int s = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();} while (c >= '0' && c <= '9') {s = s * 10 + c - '0'; c = getchar();} return s * f; } int vis[maxn][maxn][maxn][maxn]; void dfs(int cur, int x, int y, int a) { vis[cur][x][y][a]++; if (cur == n + 1) { if (x != 0 || y != 0 || a == 0 || a == n || ans <= abs(n-a-a)) return; ans = abs(n-a-a); for (int i = 1; i <= n; i++) aa[i] = fa[i]; return; } if (vis[cur+1][(x*10+s[cur]-'0'+A)%A][y][a+1] < tot) { fa[cur] = 'R'; dfs(cur+1, (x*10+s[cur]-'0'+A)%A, y, a+1); } //if (flag) return; if (vis[cur+1][x][(y*10+s[cur]-'0'+B)%B][a] < tot) { fa[cur] = 'B'; dfs(cur+1, x, (y*10+s[cur]-'0'+B)%B, a); } //if (flag) return; //aa[cur] = -1; } int main() { int T = rd(); //memset(aa, -1, sizeof(aa)); while (T--) { tot++; memset(aa, -1, sizeof(aa)); memset(vis, 0, sizeof(vis)); n = rd(), A = rd(), B = rd(); scanf("%s", s+1); s[0] = '0'; ans = 99999; dfs(1, 0, 0, 0); if (ans == 99999) { puts("-1"); } else { for (int i = 1; i <= n; i++) { putchar(aa[i]); } putchar('\n'); } } return 0; }