1. 程式人生 > 其它 >CF1593F Red-Black Number(記憶化搜尋,動態規劃)

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');
        }
    }
}

這道題告訴我,當我們面對這種搜尋規模偏大的情況下,我們可以考慮運用記憶化搜尋 + 設定變換維度 ,來達到縮小搜尋規模的目的。當動態規劃方程不太直觀時,我們可以轉為運用記憶化搜尋,從前向後更新狀態,這樣在某些題中更為直觀自然。