CF1087E. Vasya and Templates(字符串)

题目链接: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;
}
原创文章 65 获赞 3 访问量 2106

猜你喜欢

转载自blog.csdn.net/littlegoldgold/article/details/104965602
今日推荐