【题解】CF1455F String and Operations
很有意思的动态规划。
这道题的关键点在于想到用 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)\),但是细节太多就弃了/doge 。
#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;
}