Fork me on GitHub

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;
}
posted @ 2020-03-19 13:38  qjy_73  阅读(204)  评论(0)    收藏  举报