fzu 1979 福州网络赛I题

Problem Description

Given a string with uppercase letters, and you are allowed to reverse the prefix by each operation. Your task is to make the string to become the smallest one in alphabetical order at most k operations. You should note that the length of the prefix you want to reverse must be larger than the previous operation except the first operation.

 

For example, given the string "BCDAF", and you are allowed to operate at most 2 times. If you reverse the prefix of length 3 ("BCD") to get "DCBAF", and then the length of the prefix you reverse next time should be larger than 3. After reversing the prefix of length 4 ("DCBA") to get "ABCDF", and it's the smallest one in alphabetical order.

Input

The first line of the input contains an integer T (T≤50), indicating the number of cases. Each case begins with a line containing two integers N and k (0<N≤100, 0≤k≤N), the length of the string and the maximum times of operations you are allowed to do. The next line contains the string, consisting of characters 'A' to 'Z'.

Output

For each test case, print a line containing the test case number (beginning with 1) and the smallest string you make in alphabetical order.

Sample Input

2 5 1 BCDAF 5 2 BCDAF

Sample Output

Case 1: ADCBF Case 2: ABCDF

Source

The 35th ACM/ICPC Asia Regional Fuzhou Site —— Online Contest

 

题意如下:

     给出一个字符串,要求最多翻转它的前缀k次使得其字典序变成最小,但是每次翻转的前缀一定要比前一次大。

思路:

设两个数组:

1.f[s][i],表示第s轮前i个字符顺序最小的情况(如:BDCA < DBCA)。

2.g[s][i],表示第s轮前i个字符倒序最小的情况(如:DBCA < BDCA)。

每一轮翻转都记录前i个字符的最优翻转结果,状态转移可以由本轮前i-1个最小 f[s][i-1] 和上一轮的前i 个倒序最小 g[s^1][i-1] 再 翻转i个字符的较小者决定,当然也可能不做任何改动,就是f[s^1][i]。容易搞错的一个地方是:字符串的值最大翻转之后不一定最小!!比如DBCD的ascii值大于CEBA,翻转后依然是DCBD>ABEC。必须要倒序的最小才行。 

 

#include<iostream>
using namespace std;
char f[2][102][102],g[2][102][102];
 char str[102];
 int i,j,t,n,k;
void work(int d)
{
 int s=d%2,i,j,flag,k;
 f[s][d-1][0]='z',g[s][d-1][d]='z';
 for(i=d;i<n;i++)
 {

//求f[s][i]
  flag=0;
  g[s^1][i-1][i]=str[i];
  if(strcmp(f[s][i-1],f[s^1][i])>0)//本轮的最小和前一轮最小
  {
   flag=1;
   for(j=0,k=i;j<=i;j++,k--){
    if(g[s^1][i-1][k]>f[s^1][i][j]){
     break;}
    if(g[s^1][i-1][k]<f[s^1][i][j])
    { flag=2; break;}
   }
  }
  else//再和翻转之后的比较
  {
   flag=0;
   for(j=0,k=i;j<=i;j++,k--){
    if(g[s^1][i-1][k]>f[s][i-1][j]){
     break;}
    if(g[s^1][i-1][k]<f[s][i-1][j])
    { flag=2; break;}
   }
  }
  if(flag==0)//根据情况分别给F[S][I]赋值
   strcpy(f[s][i],f[s][i-1]);
  else
   if(flag==1)
    strcpy(f[s][i],f[s^1][i]);
   else{
    for(j=0,k=i;j<=i;j++,k--)
     f[s][i][j]=g[s^1][i-1][k];
   }
 /*------------------------------------------分割线-------------------------------------------------*/

//求g[s][i]
  flag=0;
  for(j=i;j>=0;j--){
   if(g[s][i-1][j]<g[s^1][i][j])
    break;
   if(g[s][i-1][j]>g[s^1][i][j])
   {flag=1;break;}
  }
  if(flag)
  {
   for(j=0,k=i;j<=i;j++,k--){
    if(f[s^1][i-1][j]>g[s^1][i][k]){
     break;}
    if(f[s^1][i-1][j]<g[s^1][i][k])
    { flag=2; break;}
   }
  }
  else
  {
   for(j=0,k=i;j<=i;j++,k--){
    if(f[s^1][i-1][j]>g[s][i-1][k]){
     break;}
    if(f[s^1][i-1][j]<g[s][i-1][k])
    { flag=2; break;}
   }
  }
  if(flag==0)
   strcpy(g[s][i],g[s][i-1]);
  else
   if(flag==1)
    strcpy(g[s][i],g[s^1][i]);
   else{
    for(j=0,k=i;j<=i;j++,k--)
     g[s][i][j]=f[s^1][i-1][k];
   }
 }
}

int main()
{
 int c=0;
 cin>>t;
 while(t--)
 {
  scanf("%d%d",&n,&k);
  scanf("%s",str);
  if(k==n)
   k=n-1;
  if(n==1 || k==0)
  {
   printf("Case %d: %s/n",++c,str);
   continue;
  }
  for(i=0;i<=n;i++)
  {
   strcpy(f[0][i],str);
   strcpy(f[1][i],str);
   strcpy(g[0][i],str);
   strcpy(g[1][i],str);
  }
  for(i=1;i<=k;i++)
   work(i);
  f[k%2][n-1][n]='/0';
  printf("Case %d: %s/n",++c,f[k%2][n-1]);
 }
 return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值