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;
}