Codeforces 1087E-Vasya and Templates
Codeforces 1087E-Vasya and Templates
题意
T组数据,每次给出一个整数k,三个字符串s,a,b(只包含前k个字母)。要求找出一个字符串p,满足以下条件:
1、是前k个字母的一个排列。
2、将p作用于s:如果s[i]是第j个字母(从'a'开始),那么将s[i]变换成p[j]。(例如:P="badc",s="bbcb"。s[1]='b'是第2个字母,所以s[1]变换成p[2]='a',同理,s经过p的作用后变成"aada")。
3、经过P作用后的S满足字典序\(a \leq s \leq\) b。
如果存在这样的P,输出YES以及字符串P,否则输出NO。
题解
想要直接找到一个字符串令其字典序在a,b之间不好做,我们可以找到一个大于等于a的最小的字符串,如果它满足小于等于b,那么成立,反之不存在。
我们从最高位开始往后,让前面的尽可能相等,会出现四种情况:
1、s[i]之前没出现过并且a[i]也没使用过,那么p[s[i]]=a[i],f[a[i]]=s[i],继续。
2、s[i]之前出现过并且p[s[i]]正好等于a[i],继续。
3、s[i]之前出现过但是p[s[i]]>a[i],那么此时已经能保证变换后的s>a,所以接下来的变换只要尽可能地小即可。
4、s[i]之前没出现过,但是a[i]用过,那么从当前位置开始,往前找,如果有某个位置j,能将s[j]变换成大于a[j]的字符,那么就停止,此时s>a,在j之后的变换尽可能的小。(记得统计s[j]出现过的次数,如果在1~j中已经没有出现,那么需要将之前的变化p[s[j]]=0,f[a[j]]=0)。
最后,判断变换后的字符串是否小于等于b,如果满足,将P中其余没填的位置任意补全并输出,否则NO。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int T,k,n;
char str[N];
char s[N],a[N],b[N];
int p[30],cnt[30],f[30];
//p[i]表示第i个字母被传换成p[i],cnt[i]表示第i个字母出现的次数,f[i]是p[i]的反
int main(){
scanf("%d",&T);
while(T--){
memset(p,0,sizeof(p));
memset(cnt,0,sizeof(cnt));
memset(f,0,sizeof(f));
scanf("%d",&k);
scanf("%s%s%s",s+1,a+1,b+1);
n=strlen(s+1);
for(int i=1;i<=n;i++){
s[i]-='a'-1;
a[i]-='a'-1;
b[i]-='a'-1;
}
int flag=0;
int idx=0;
for(int i=1;i<=n;i++){
cnt[s[i]]++;
if(!p[s[i]]&&!f[a[i]]){
p[s[i]]=a[i];
f[a[i]]=s[i];
}else if(p[s[i]]==a[i]) continue;
else if(p[s[i]]>a[i]){
flag=1;
idx=i;
break;
}else{
flag=2;
idx=i;
break;
}
}
bool ok=1;
if(!flag){
int i=1;
for(;i<=n;i++){
if(p[s[i]]!=b[i]) break;
}
if(p[s[i]]>b[i]) ok=0;
}else if(flag==1){
for(int i=idx+1;i<=n;i++){
if(!p[s[i]]){
for(int j=1;j<=k;j++){
if(!f[j]){
p[s[i]]=j;
f[j]=s[i];
break;
}
}
}
}
int i=1;
for(;i<=n;i++){
if(p[s[i]]!=b[i]) break;
}
if(p[s[i]]>b[i]) ok=0;
}else{
bool ff=0;
int tmp=idx;
while(idx>=1){
cnt[s[idx]]--;
if(!cnt[s[idx]]){
if(idx!=tmp){
p[s[idx]]=0;
f[a[idx]]=0;
}
for(int i=a[idx]+1;i<=k;i++){
if(!f[i]){
f[i]=s[idx];
p[s[idx]]=i;
ff=1;
break;
}
}
}
if(ff) break;
idx--;
}
if(ff){
for(int i=idx+1;i<=n;i++){
if(!p[s[i]]){
for(int j=1;j<=k;j++){
if(!f[j]){
p[s[i]]=j;
f[j]=s[i];
break;
}
}
}
}
int i=1;
for(;i<=n;i++){
if(p[s[i]]!=b[i]) break;
}
if(p[s[i]]>b[i]) ok=0;
}else ok=0;
}
if(ok){
printf("YES\n");
for(int i=1;i<=k;i++){
if(!p[i]){
for(int j=1;j<=k;j++){
if(!f[j]){
f[j]=i;
p[i]=j;
break;
}
}
}
}
for(int i=1;i<=k;i++){
printf("%c",p[i]+'a'-1);
}
printf("\n");
}else{
printf("NO\n");
}
}
return 0;
}

浙公网安备 33010602011771号