循環クエスト
\ [制限時間:3000ミリ秒\クアッドメモリの制限:524288キロバイト\]
問題の意味
文字列を与えられた\(S \)文字列、続いて\(T \)クエリ、与えられた列挙\(T \)文字列を取得し、\(T \)をすべてのサイクルの部分文字列に(\ S \)番号の文字列が表示されます。
考え
各クエリ文字列の場合、すべてのサイクルをサブストリングので、あなたが置くことができるように\(T \)追求するそのコピーの末尾に文字列を、および\(LCS \) 。
- 場合\(P \)ノード照会\(TLEN LCS == \) 、次いで\(P \)を条件に表されるサブストリングは、一周期含む\(T \)文字列。
- 場合\(LCS> TLEN \) 、それが示す\(P \)は、ループ含む\(T \)文字列が、周期の一致よりも長い\(T \)文字列、その次に、文字列必須の寄与\(父\)に、私たちは、一時変数の作成\(TMP \)をする(父\)\この文字列の貢献を見つけるためにジャンプします。
- 最後に、限り、各ノードの出現の計算された数は、サブストリングが含まれ、これらの値は一緒に条件を満たしています。
ここでは見つける\(LCS \)中間変数と直接\(RES \)の代わりに\(父\)のアップデート。例えば、私は今、ノード\(U \) 、および\(父[P-] = U \)、そう\(P \)で\(U \)である\(LCS \)より一層、\(U \)そのに\(父\)実際には、更新処理と\(のp \)にする(父\)\アップデートプロセスを同じであるノードの寄与がある限り、一度数えながら、最終的にはそう、同じノードに留まります(\ U \)実際には、最大更新されない場合があります。
この問題は、クエリました\(1E5を\) 、および照会の合計の長さでした(1E6の\)\、それは多くのことができ、各クエリ文字列のショートが発生し、そう\(VIS \)私は行くたびに\( memsetのの\は)します(TLE \)\皮肉のを...
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lowbit(x) x & (-x)
#define mes(a, b) memset(a, b, sizeof a)
#define fi first
#define se second
#define pii pair<int, int>
#define INOPEN freopen("in.txt", "r", stdin)
#define OUTOPEN freopen("out.txt", "w", stdout)
typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 1e6 + 10;
const int maxm = 1e5 + 10;
const ll mod = 1e9 + 7;
const ll INF = 1e18 + 100;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
using namespace std;
int n, m;
int cas, tol, T;
struct Sam {
int node[maxn<<1][27], step[maxn<<1], fa[maxn<<1];
int dp[maxn<<1], tax[maxn<<1], gid[maxn<<1];
int vis[maxn<<1];
int last, sz;
int newnode() {
mes(node[++sz], 0);
dp[sz] = step[sz] = fa[sz] = 0;
return sz;
}
void init() {
sz = 0;
last = newnode();
}
void insert(int k) {
int p = last, np = last = newnode();
dp[np] = 1;
step[np] = step[p]+1;
for(; p&&!node[p][k]; p=fa[p])
node[p][k] = np;
if(p==0) {
fa[np] = 1;
} else {
int q = node[p][k];
if(step[q] == step[p]+1) {
fa[np] = q;
} else {
int nq = newnode();
memcpy(node[nq], node[q], sizeof(node[q]));
fa[nq] = fa[q];
step[nq] = step[p]+1;
fa[np] = fa[q] = nq;
for(; p&&node[p][k]==q; p=fa[p])
node[p][k] = nq;
}
}
}
void handle() {
for(int i=0; i<=sz; i++) tax[i] = 0;
for(int i=1; i<=sz; i++) tax[step[i]]++;
for(int i=1; i<=sz; i++) tax[i] += tax[i-1];
for(int i=1; i<=sz; i++) gid[tax[step[i]]--] = i;
for(int i=sz; i>=1; i--) {
int u = gid[i];
dp[fa[u]] += dp[u];
}
}
int solve(char *s, int len, int id) {
int p = 1, res = 0;
int ans = 0;
for(int i=1; i<=len+len; i++) {
int k = s[i]-'a'+1;
while(p && !node[p][k]) {
p = fa[p];
res = step[p];
}
if(p == 0) {
p = 1;
res = 0;
} else {
p = node[p][k];
res++;
if(res >= len) {
int tmp = p;
while(vis[tmp]!=id &&!(step[fa[tmp]]+1<=len && len<=step[tmp])) {
vis[tmp] = id;
tmp = fa[tmp];
}
if(vis[tmp] != id) {
vis[tmp] = id;
ans += dp[tmp];
}
}
}
}
return ans;
}
} sam;
char s[maxn], t[maxn<<1];
int main() {
scanf("%s", s+1);
int slen = strlen(s+1);
sam.init();
for(int i=1; i<=slen; i++) {
sam.insert(s[i]-'a'+1);
}
sam.handle();
scanf("%d", &T);
for(int tt=1; tt<=T; tt++) {
scanf("%s", t+1);
int tlen = strlen(t+1);
for(int i=1; i<=tlen; i++) {
t[i+tlen] = t[i];
}
t[tlen+tlen+1] = '\0';
int ans = sam.solve(t, tlen, tt);
printf("%d\n", ans);
}
return 0;
}