题意 : 如果一个字符串包含两个相邻的重复子串,则称它是“容易的串”,其他串称为“困难的 串”。例如,BB、ABCDACABCAB、ABCDABCD都是容易的串,而D、DC、ABDAB、 CBABCBA都是困难的串。程序从输入中读取多行数据,每行包括两个整数n和L(即按此顺序给出),其中n > 0,L的范围是1 ≤ L ≤ 26。根据这些输入,程序要按照字母表升序打印出第n个“hard”字串(由字母表中的前L个字母构成),并在接下来的一行打印这个串的长度。按照上述规则,第一个串应该是“A”。对于给定的n和L,保证第n个“hard”串是一定存在的。比方说,当L = 3时,头7个“hard”字串为:
A
AB
ABA
ABAC
ABACA
ABACAB
ABACABA
分析 : 考虑使用深搜暴力一个个构造出合法的困难串,在深搜时按字典序考虑构造序列的每一位即可。但是有个难点,就是如何判断是否有重复?紫书给出了很好的解释=》“一种方法是检查所有长度为偶数的子串,分别判断每个字串的前一半是否等于后 一半。尽管是正确的,但这个方法做了很多无用功。还记得八皇后问题中是怎么判断合法性 的吗?判断当前皇后是否和前面的皇后冲突,但并不判断以前的皇后是否相互冲突——那些 皇后在以前已经判断过了。同样的道理,我们只需要判断当前串的后缀,而非所有子串。”换句话说就是在每判断一个位置的时候,我们只要枚举并检查含有新添加字母的偶数串合法后缀(也就是串的长度不要超过总长),就像书上说的,因为是一个个字母递增添加构造的,所以每一个都有和前面的进行判断,故只考虑当前而不考虑之前。
#include<bits/stdc++.h>
using namespace std;
int k, L;
char * letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int ans;
bool check(char *temp, int last)
{
for(int j=1; 2*j<=last+1; j++){//->learn
bool Equal = true;
for(int k=0; k<j; k++){
if(temp[last-j+1+k] != temp[last-2*j+1+k]) {Equal = false;break;}
//if(temp[last-k] != temp[last-k-j]) {Equal = false;break;}//也可以
}
if(Equal) return false;
}
return true;
}
int cnt = 0;
inline void DFS(int num, char *temp)
{
if(ans!=-1) return ;
if(cnt==k) { temp[num]='