acm-(好题、思维、字典序、分类讨论)Educational Codeforces Round 99 (Rated for Div. 2) F. String and Operations

题面
传送门
考虑当前位于第 i i i位,如何让该位的字母最小,假设 1 ∼ i − 1 1\sim i-1 1i1的字母已经固定并且无法在再改变,而第 i + 1 ∼ n i+1\sim n i+1n位的字母和顺序都还未被改变,第 i i i位上的字母可能被改变,也可能没有被改变,令 f g fg fg 1 1 1表示未被改变,也就是说在该位置上还有一次操作可使用,否则代表被改变,即第 i i i位不具有操作可用。

f ( c ) f(c) f(c)表示字母 c c c经过 u p / d o w n / 0 up/down/0 up/down/0操作后可以变成的最小字母(若 f g = 0 fg=0 fg=0那么 f ( c ) = c f(c)=c f(c)=c),特别地有 f ( ′ a ′ ) = ′ a ′ f('a')='a' f(a)=a。那么第 i i i位的字母只可能是 f ( s [ i ] ) , f ( s [ i + 1 ] ) , s [ i + 2 ] f(s[i]),f(s[i+1]),s[i+2] f(s[i]),f(s[i+1]),s[i+2]其中一个( s [ i + 3 ] s[i+3] s[i+3]必不可能到达第 i i i位)。

  1. s [ i + 2 ] < m i n { f ( s [ i ] ) , f ( s [ i + 1 ] ) } s[i+2]<min\{f(s[i]),f(s[i+1])\} s[i+2]<min{f(s[i]),f(s[i+1])},我们就把 s [ i + 2 ] s[i+2] s[i+2]移动到当前位置。具体来说,经过三次操作后则我们能得到 i , i + 1 , i + 2 i,i+1,i+2 i,i+1,i+2位置上的字母为 s [ i + 2 ] , f ( s [ i ] ) , s [ i + 1 ] s[i+2],f(s[i]),s[i+1] s[i+2],f(s[i]),s[i+1]、。此时第 i + 1 , i + 2 i+1,i+2 i+1,i+2位置上的操作次数已经被消耗, i + 1 i+1 i+1位置上的字母无法被改变,因此我们跳过 i + 1 i+1 i+1位置到达 i + 2 i+2 i+2位置考虑第 i + 2 i+2 i+2位上的字母可以最小是多少,此时要设置 f g = 0 fg=0 fg=0
  2. f ( s [ i + 1 ] ) < f ( s [ i ] ) f(s[i+1])<f(s[i]) f(s[i+1])<f(s[i])且条件一不被满足,那么我们把 f ( s [ i + 1 ] ) f(s[i+1]) f(s[i+1])移动到当前位置,不过需要注意的是,当 f g = 0 fg=0 fg=0的时候,意味着 s [ i ] s[i] s[i]无法移动到第 i + 1 i+1 i+1位,因此只能 s [ i + 1 ] s[i+1] s[i+1]移动过来,这样的话 s [ i + 1 ] s[i+1] s[i+1]无法变成 f ( s [ i + 1 ] ) f(s[i+1]) f(s[i+1]),不过即使这样最坏情况也是两者相等,所以不影响结果,因此我们让 s [ i + 1 ] s[i+1] s[i+1]移动到第 i i i位,根据 f g = 0 fg=0 fg=0还是 f g = 1 fg=1 fg=1选择 s [ i ] = s [ i + 1 ]   o r   f ( s [ i + 1 ] ) s[i]=s[i+1]\,or\,f(s[i+1]) s[i]=s[i+1]orf(s[i+1])即可, s [ i + 1 ] s[i+1] s[i+1]也根据 f g = 0 fg=0 fg=0 f g = 1 fg=1 fg=1进行相应地设置即可,不过设置完后仍然要让 f g = 0 fg=0 fg=0,因为第 i + 1 i+1 i+1位的操作是左移,已经将操作次数消耗完了。
  3. 如果上述两种情况都不满足,那么让 s [ i ] = f ( s [ i ] ) s[i]=f(s[i]) s[i]=f(s[i])即可,此时设置 f g = 1 fg=1 fg=1然后考虑下一位的情况即可。

char s[maxn],ans[maxn];
int k,n;
char f(char c){
	if(c-'a'+1==k || c-'a'==0)return 'a';
	return c-1;
}

int main(){
	int t=rd();
	while(t--){
		n=rd(),k=rd();
		rds(s+1);
		s[n+1]='\0'; 
		int tot=0,fg=1;
		FOR(i,1,n){
			char a=fg?f(s[i]):s[i];
			char b=fg?f(s[i+1]):s[i+1];
			fg=0;
			if(i+2<=n && min(a,b)>s[i+2]){
				ans[tot++]=s[i+2];
				ans[tot++]=a;
				s[i+2]=s[i+1];
				i++;
			}else if(b<a){
				ans[tot++]=b;
				s[i+1]=b==s[i+1]?a:s[i];
			}else {
				ans[tot++]=a;
				fg=1;
			}
		}
		ans[tot++]=fg?f(s[n]):s[n];
		ans[tot]='\0';
		wrsn(ans);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值