一、题意

如果一个字符串包含两个相邻的重复子串,则称它为容易的串。
输入k和L, 要求输出由前L个字母组成的、字典序第k小的困难的串。

二、解析

通过回溯法按字典序枚举字符串,每次枚举都对应这当前字符串的最后一个字符。因此判断是否是困难的串时,就可以只判断当前字符串的后缀有没有出现相邻的重复子串即可。
这个原理就像是:八皇后问题中,只需要判断新皇后和之前的皇后有无冲突,而不需要判断以前的皇后是否相互冲突。

三、代码

#include <iostream>
#include <string>
using namespace std;
int k, L, cnt;
string ans;
bool ok = 0;

void output(int idx) {
    int cnt = 0;
    for(int i = 0; i <= idx; i ++) {
        if(i && i % 4 == 0) {
            cnt ++;
            if(cnt % 16) cout << " ";
            else cout << "\n";
        }
        cout << ans[i];
    }
    cout << "\n" << idx + 1 << endl;
}

bool isOK(int n) {
    for(int len = 1; len * 2 <= n; len ++) {
        if(ans.substr(n - len, len) == ans.substr(n - 2 * len, len)) return 0;
    }
    return 1;
}

void solve(int idx, char cur) {
    if(idx < ans.size()) ans[idx] = cur;
    else ans += cur;
    if(!isOK(idx + 1)) return;

    cnt ++;
    if(cnt == k) {
        ok = 1, output(idx);
        return;
    }
    for(int i = 0; !ok && i < L; i ++) solve(idx + 1, 'A' + i);
}

int main() {
    while(cin >> k >> L && k) {
        ok = 0, cnt = 0;
        ans.clear();
        for(int i = 0; i < L; i ++) solve(0, 'A' + i);
    }
}

四、归纳

  • 当需要按照字典序枚举字符串时,优先考虑回溯法
  • 当需要维护一个字符串时,即可以考虑用char数组,也可以考虑用string, 这一题我用的string,因为string判断困难串代码量比较少。