题目链接:见这里
题意:n个长度为k的字符串,首尾相接,按顺时针顺序写在一张CD上,每个字符串只写一次总字符串长度小于1e6。保证每个字符串不同。这样CD上就有了一个环形字符串,长度是n*k。又给出g个长度为k的字符串列表(编号从1到g),按照顺时针打印CD上字符串的编号。保证每个字符串不同。保证这g个字符串长度的和小于2*1e6。
下面代码和思路参考了Wannafly每日一题,顺便学会了Hash。记录了模板。
解题思路:可以发现,如果枚举第一个串的开始位置,由于输入的g个串,长度都为k,那么每个串的位置就固定了。那么我只要知道,在主串上那一段位置的字符串,是否存在在g个串中,然后如果每个都存在,那么就是符合的。这一部分可以用字符串hash做到O(1)判断。复杂度的话,枚举第一个串的复杂度是k,一共需要匹配n个字符串,所以总复杂度是O(nk)。要注意不能用自然溢出写,因为可以造出数据卡掉自然溢出。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
const int N = 2e6 + 5;
const int seed = 131;
int mod[2] = {1000000007, 1000000009};
char S[N]; //输入字符串
int F[2][N]; //seed ^ a
int pre[2][N];
int n, g, w;
int tim, vis[N], ans[N];
map <pii, int> cnt;

void pre_init(){ //deal with seed ^ n
    for(int t = 0; t <= 1; t++){
        F[t][0] = 1;
        for(int i = 1; i < N; i++){
            F[t][i] = (LL)F[t][i-1] * seed % mod[t];
        }
    }
}

pii Hash(string s){ //Hash a string
    int ret[2] = {0};
    int len = s.size();
    for(int t = 0; t <= 1; t++){
        for(int i = 0; i < len; i++){
            ret[t] = ((LL) ret[t] * seed + s[i]) % mod[t];
        }
    }
    return pii(ret[0], ret[1]);
}

pii Hash(int l, int r)
{
    int ret[2];
    for(int t = 0; t <= 1; t++){
        ret[t] = (pre[t][r] - (LL)pre[t][l-1] * F[t][r-l+1] % mod[t] + mod[t]) % mod[t];
    }
    return pii(ret[0], ret[1]);
}

void pre_solve(){
    int len = strlen(S + 1);
    for(int t = 0; t <= 1; t++){
        pre[t][0] = 0;
        for(int i = 1; i <= len; i++){
            pre[t][i] = ((LL)pre[t][i-1] * seed + S[i]) % mod[t];
        }
        for(int j = len + 1, i = 1; i <= w - 1; i++, j++){
            pre[t][j] = ((LL)pre[t][j-1] * seed + S[i]) % mod[t];
        }
    }
}

bool check(int id){
    tim++;
    int l = id, r = id + w - 1;
    for(int i = 1; i <= n; i++, l += w, r += w){
        pii t = Hash(l, r);
        if(!cnt.count(t)) return 0; //目标串中没有这个子串
        int p = cnt[t];
        if(vis[p] == tim) return 0; //目标串出现了大于1次
        vis[p] = tim; ans[i] = p;
    }
    printf("YES\n");
    for(int i = 1; i <= n; i++) cout << ans[i] <<" "; cout << endl;
    return 1;
}

int main()
{
    pre_init();
    scanf("%d%d%s", &n, &w, S+1);
    pre_solve();
    scanf("%d", &g);
    for(int i = 1; i <= g; i++){
        scanf("%s", S);
        pii t = Hash(S);
        cnt[t] = i;
    }
    bool mark = 0;
    for(int i = 1; i <= w; i++){
        if(check(i)){
            mark = 1;
            break;
        }
    }
    if(mark == 0){
        printf("NO\n");
    }
    return 0;
}