1. 程式人生 > 其它 >【題解】CF1455F String and Operations

【題解】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;
}