题目链接:https://vjudge.net/problem/CodeForces-1087E/origin
https://vjudge.net/contest/362376#problem/C
题意:构造一个长度为k的字符串p,将字符串s变化成为一个新串,使得s串字典序大于等于a,小于等于b。其中变化规则是s’[i]=p[s[i]],s[i]=s[i]-‘a’+1。s a b p串中只有字母表前k个字母。
解题思路:
先找出大于等于a的最小字符串,然后与b进行比较(有点像贪心)
具体找大于等于a的最小字符串,先找与a字符串相同前缀的最大长度,直到无法匹配,然后进行回溯,找到第一个可以变化成稍微大一点的点(原来对应a[i],现在从a[i]+1开始寻找找到一个未被使用的字母),之后就比较简单了,直接令i之后的点都尽可能取最小字母就行。
(参考:https://blog.csdn.net/Cold_Chair/article/details/85269495)
这个题细节点有点多:
1.注意将s全部匹配完,p字符串不一定全部都用到,对于没用到的位置,随便赋一个值就行
2.对于p[] used[] alp[]数组进行初始化时,for循环上界不要写26了,写k,我因为这个超时了
3.循环比较多,设置的变量也比较多,注意不要写错
…
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
char s[1100000],a[1100000],b[1100000];
int ss[1100000],aa[1100000],bb[1100000];
int p[27],used[27],alp[27]; //p记录p字符串中的字符 used记录s中大小为i的字符的个数 alp记录第i个字母在p中的什么位置
int len;
int k;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&k);
scanf("%s",s+1);
scanf("%s",a+1);
scanf("%s",b+1);
len=strlen(s+1);
//初始化
for(int i=0;i<=k;i++)
p[i]=-1,used[i]=0,alp[i]=-1;
//将字符串转化为int型
for(int i=1;i<=len;i++)
{
ss[i]=s[i]-'a'+1;
aa[i]=a[i]-'a'+1;
bb[i]=b[i]-'a'+1;
}
//寻找大于等于a的字典序最小的字符串
//先找到可以与a相等的最远字符位x
int x;
for(x=1;x<=len;x++)
{
used[ss[x]]++;
//目前s[i]在p中无匹配,并且a[i]未被使用
if(p[ss[x]]==-1&&alp[aa[x]]==-1)
{
p[ss[x]]=aa[x];
alp[aa[x]]=ss[x];
continue;
}
if(p[ss[x]]==aa[x])
continue;
break;
}
if(x<=len)
{
int xx=x;
used[ss[xx]]--;
for(;xx>0;xx--)
{
if(p[ss[xx]]>aa[xx])
break;
//注意这个地方xx!=x 因为x位置处本身就无匹配
if(xx!=x)
{
used[ss[xx]]--;
if(used[ss[xx]]==0)
alp[aa[xx]]=-1,p[ss[xx]]=-1;
}
if(p[ss[xx]]!=-1)
continue;
int temp=-1;
//从当前无匹配位置开始找到稍微大一点的匹配(包括x)
for(int i=aa[xx]+1;i<=k;i++)
{
if(alp[i]==-1)
{
temp=i;
break;
}
}
//如果当前xx找不到合适匹配则继续进行
if(temp==-1)
continue;
p[ss[xx]]=temp;
alp[temp]=ss[xx];
break;
}
//如果回溯到最后都没有找到合适的替换
if(xx==0)
{
printf("NO\n");
continue;
}
//因为第xx位已经匹配到一个比a[i]大的字符,为了保证p字典序最小,直接给xx位之后依次赋予最小的字符即可
for(int i=xx+1;i<=len;i++)
{
if(p[ss[i]]!=-1)
continue;
for(int j=1;j<=k;j++)
if(alp[j]==-1)
{
p[ss[i]]=j;
alp[j]=ss[i];
break;
}
}
}
//p字符串可能未匹配完全
for(int i=1;i<=k;i++)
{
if(p[i]==-1)
{
for(int j=1;j<=k;j++)
{
if(alp[j]==-1)
{
p[i]=j;
alp[j]=i;
break;
}
}
}
}
int flag=0;
for(int i=1;i<=len;i++)
{
if(p[ss[i]]<bb[i])
break;
if(p[ss[i]]>bb[i])
{
flag=1;
break;
}
}
if(flag==1)
printf("NO\n");
else
{
printf("YES\n");
for(int i=1;i<=k;i++)
printf("%c",'a'+p[i]-1);
printf("\n");
}
}
return 0;
}