給定,給定一個長爲的環形字符串,已知它由個長爲的互不相同字符串相接而成。
再給定個長爲的字符串,兩兩不同,總長不超過.
問環形字符串是由哪些字符串首尾相接(每個字符串只能出現一次)組成的,輸出時可以選定任意的起點,無解輸出。
將環形字符串展開到長度,因爲所有字符串長度相等,所以每個位置只會匹配一個模式串。用AC自動機找到每個位置所匹配的編號。
把位置按模分組,對於每個模數的個位置,看看是否有重複的模式串編號,如果沒有就是一組解。
這是2300的最後一道題目,感覺2300以下的題有不少kmp的好題,但是一旦涉及自動機就會變得模板了起來,qwq.
/* LittleFall : Hello! */
#include <bits/stdc++.h>
using namespace std; using ll = long long; inline int read();
const int M = 2500016, MOD = 1000000007;
//Trie樹(圖)/是否爲終結點/失配鏈接/後綴鏈接,都是節點的屬性
int sz = 0;
int ch[M][26], ed[M], fail[M], last[M];
// 向Trie樹中嘗試插入一個模式串, 返回插入後的節點編號
void insert(const char *s, int id)
{
int u = 0;
for(int i = 0; s[i]; i++)
{
int &v = ch[u][s[i] - 'a'];
if(!v) v=++sz;
u = v;
}
ed[u] = id;
}
void build(const char *s, vector<int> *match, int k)
{
queue<int> q;
for(int v:ch[0]) if(v)
fail[v] = 0, q.push(v);
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i = 0; i < 26; i++)
{
int &v = ch[u][i];
if(v)
{
q.push(v);
fail[v] = ch[fail[u]][i];
last[v] = ed[fail[v]] ? fail[v] : last[fail[v]]; //後綴鏈接
}
else v = ch[fail[u]][i]; //建立trie圖
}
}
int now = 0;
for(int i = 0; s[i]; i++)
{
now = ch[now][s[i] - 'a'];
int id = ed[now] ? now : last[now];
if(ed[id]) match[i%k].push_back(ed[id]); //最多隻會匹配一個
}
}
char str[M], pat[M];
vector<int> match[100016]; //每個模數依次匹配的編號
int tag[M];
int main(void)
{
#ifdef _LITTLEFALL_
freopen("in.txt","r",stdin);
#endif
int n = read(), k = read(), m = n*k+k-1;
scanf("%s", str);
for(int i=n*k; i<m; ++i)
str[i] = str[i-n*k];
int g = read();
for(int i=1; i<=g; ++i)
{
scanf("%s", pat);
insert(pat, i);
}
build(str, match, k);
memset(tag, -1, sizeof(tag));
for(int i=0; i<k; ++i) if((int)match[i].size()==n)
{
int suc = 1;
for(auto x:match[i])
{
if(tag[x]==i)
{
suc = 0;
break;
}
tag[x] = i;
}
if(suc)
{
printf("YES\n");
for(auto x:match[i])
printf("%d ",x );
return 0;
}
}
printf("NO\n");
return 0;
}
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}