Codeforces1455F.String and Operations 字符串dp
Codeforces1455F.String and Operations
题意
给定一个长度为(n)的字符串(s),字符集大小为(k),有(n)次操作,第(i)次操作会对原本在(s)中第(i)位的字符做如下四种之一的操作:
- (L) ,和字符串中前一位字符交换。
- (R),和字符串中后一位字符交换。
- (D),将该字符变为字符集中的下一位字符。
- (U),将该字符变为字符集中的上一位字符。
- (0),什么都不做。
分析
通过分析可以得出,原本在第(i)位的字符最多可以向左移动到第(i-2)位,通过在第(i-1,i-2)位字符连续做(RL)操作。
(s[i-2]s[i-1]s[i]->s[i-2]s[i]s[i-1]->s[i]s[i-2]s[i-1])
设(dp[i])为操作前(i)位得到的字典序最小的字符串。
(dp[i])通过对第(i+1)位字符做(D~or~U~or~L~or~0)操作,转移到(dp[i+1]),
(dp[i])通过对第(i+1,i+2)位字符连续做(RD~or~RU~or~R0~or~RL)操作,转移到(dp[i+2]) 。
Code
#include<bits/stdc++.h>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,p<<1|1
#define pii pair<int,int>
#define lson l,mid,p<<1
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const int mod=1e9+7;
const int N=1e5+10;
const int inf=1e9;
int t,n,k;
char s[510];
string dp[510];
int main(){
ios::sync_with_stdio(false);
//freopen("in","r",stdin);
cin>>t;
while(t--){
cin>>n>>k;
cin>>s+1;
rep(i,0,n) dp[i].clear();
rep(i,1,n) dp[i].pb('~');
rep(i,0,n-1){
char c=s[i+1];
c=min({c,char((s[i+1]-'a'+k-1)%k+'a'),char((s[i+1]-'a'+1)%k+'a')});
dp[i+1]=min(dp[i+1],dp[i]+c);//D or U
dp[i+1]=min(dp[i+1],dp[i].substr(0,i-1)+s[i+1]+dp[i].back()); //L
if(i==0) continue;
dp[i+1]=min(dp[i+1],dp[i-1]+c+s[i]); //RD or RU or R0
dp[i+2]=min(dp[i+2],dp[i].substr(0,i-1)+s[i+2]+dp[i].back()+s[i+1]);//RL
}
cout<<dp[n]<<endl;
}
return 0;
}