题目链接
题目大意
有两个长度为2的由‘a’ ‘b’ ‘c’三个字母构成的字符串,现在需要构造一个由’a’,‘b’,‘c’,三个字母各n个组成的字符串,且构成的字符串不包含前两个字符串的子串
题目思路
emm。。。。比较神奇
标准题解是说首先生成a、b、c的6个全排列,然后,每种全排列以两种方式扩大n倍——举个例子,n为3时,对于acb,可以扩展成这两种:acbacbacb、aaacccbbb。然后依次检查这12种字符串是否有满足要求的,我一直很疑惑为什么只要这12种构造方法就行了。后面终于搞懂了
证明:
这题是个图论.s,t表示不能走的路.比如,当s="ab“时,表示路径a→b是不通的…因为只有s,t,两个字符串,所以可以得出一个3个顶点,7条边((包括顶点到自己的边))的图…
然后分类讨论:
1:三个顶点都能通过一条边回到自己
这样我们可以构造一种格局使得第一与第二个点联通且第二与第三个点联通,构造出后分别重复n次即可:
举个例子:
3
a b
b c
答案:aaacccbbb
2:三个顶点无法都能通过一条边回到自己::
这样我们可以构造一种格局使得第一与第二个点联通且第二与第三个点联通且第一与第三个点联通,构造出后集体重复n次即可
举个例子::、
3
a a
b c
答案:cbacbacba
代码
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define debug printf("I am here\n");
using namespace std;
typedef long long ll;
const int maxn=3e5+5,mod=2147493647,inf=0x3f3f3f3f;
int n;
char s1[3],s2[3],s[maxn],per[6][5]={"abc","acb","bac","bca","cab","cba"};
void check(){
for(int i=1;i<=3*n-1;i++){
if((s[i]==s1[0]&&s[i+1]==s1[1])||(s[i]==s2[0]&&s[i+1]==s2[1])){
return ;
}
}
s[3*n+1]='\0';
printf("YES\n%s\n",s+1);
exit(0);
}
int main(){
scanf("%d %s %s",&n,s1,s2);
for(int i=0;i<6;i++){
for(int j=1;j<=3*n;j++){
s[j]=per[i][(j-1+n)%3];
}
check();
for(int j=1;j<=3*n;j++){
s[j]=per[i][(j-1)/n];
}
check();
}
printf("NO\n");
return 0;
}
参考链接:https://www.luogu.com.cn/blog/Guess00/solution-CF1213E