【題解】CF1455F String and Operations
阿新 • • 發佈:2021-10-04
很有意思的動態規劃。
這道題的關鍵點在於想到用 string
作為動態規劃的 \(f\) 陣列。
首先前 \(i\) 次操作只能影響前 \(i+1\) 個位置,所以我們定義狀態 \(f[i]\) 表示前 \(i\) 次操作,前 \(i+1\) 個位置字典序最小的串。
對於 OUDR
操作,直接模擬一下即可。
但是對於 L
操作,我們發現還會影響前面的位置。
但是觀察到第 \(i\) 個操作最多影響到位置 \(i-2\) ,而只有連續的 RL
操作可以做到。
所以我們再記錄一下上一個操作是不是 R
即可。時間複雜度 \(\mathcal{O}(T n^2)\) 。事實上只用記錄最後三位即可做到 \(\mathcal{O}(Tn)\)
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) #define pre(i,a,b) for(int i=a;i>=b;i--) #define N 505 using namespace std; int n,k;char s[N];string f[N][2]; char nx(char ch){return 'a' + (ch - 'a' + 1) % k;} char pr(char ch){return 'a' + (ch - 'a' + k - 1) % k;} string g(string x,int i,int op){ if(x == "~")return x; if(!op) x[i-1] = nx(x[i-1]); else x[i-1] = pr(x[i-1]); return x; } string sp(string x,int i){ if(x == "~")return x; swap(x[i-1],x[i-2]); return x; } void solve(){ scanf("%d%d",&n,&k); scanf("%s",s + 1); f[0][0] = "";f[0][1] = "~"; f[0][0] += s[1]; rep(i, 1, n){ // O f[i][0] = min(f[i-1][1], f[i-1][0]); // U f[i][0] = min(f[i][0], min(g(f[i-1][0], i, 0), g(f[i-1][1], i-1, 0))); // D f[i][0] = min(f[i][0], min(g(f[i-1][0], i, 1), g(f[i-1][1], i-1, 1))); // L if(i > 1)f[i][0] = min(f[i][0], sp(f[i-1][0], i)); if(i > 2)f[i][0] = min(f[i][0], sp(f[i-1][1], i-1)); // R if(i < n)f[i][1] = sp(f[i - 1][0] + s[i + 1],i + 1); if(i < n)f[i][0] += s[i + 1]; } cout<< f[n][0] <<endl; } int main(){ int T;scanf("%d",&T); while(T--)solve(); return 0; }