Loading

【题解】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;
}
posted @ 2021-10-04 16:59  7KByte  阅读(31)  评论(0编辑  收藏  举报