题意
给字符串 s s s 和 t t t,你需要给 s s s 拍若干张照片,然后把它们按某种顺序拼起来得到字符串t,求最少拍多少张照片、其实就是在找最少需要多少原串中的子串构成询问串。
每次贪心地选择极长的一段拍照, S A M SAM SAM进行匹配就行了。
AC代码:
const int N = 500010;
struct SAM
{
struct node
{
int parent, next[26], len;
int cnt;
};
node tr[N];
int sz[N];
int rnk[N];
int last = 0;
int num = 0;
void init()
{
last = 0;
num = 0;
tr[0].parent = -1;
}
void add(char ch)
{
int p = last;
int t = ch - 'A';
int now = ++num;
tr[now].len = tr[last].len + 1;
tr[now].cnt = 1;
while (p != -1 && tr[p].next[t] == 0)
{
tr[p].next[t] = now;
p = tr[p].parent;
}
if (p != -1)
{
int q = tr[p].next[t];
if (tr[p].len + 1 == tr[q].len)
{
tr[num].parent = q;
}
else
{
tr[++num].parent = tr[q].parent;
memcpy(tr[num].next, tr[q].next, sizeof(tr[num].next));
tr[num].len = tr[p].len + 1;
while (p != -1 && tr[p].next[t] == q)
{
tr[p].next[t] = num;
p = tr[p].parent;
}
tr[now].parent = tr[q].parent = num;
}
}
else
tr[now].parent = 0;
last = now;
}
void solve()
{
for (int i = 0; i <= num; ++i)
sz[i] = 0;
for (int i = 0; i <= num; ++i)
sz[tr[i].len]++;
for (int i = 1; i <= num; ++i)
sz[i] += sz[i - 1];
for (int i = 0; i <= num; ++i)
rnk[--sz[tr[i].len]] = i;
for (int i = num; i >= 1; --i)
{
tr[tr[rnk[i]].parent].cnt += tr[rnk[i]].cnt;
}
}
int getAns(char ch[], int len)
{
int ans = 1;
int now = 0;
for (int i = 0; i < len; ++i)
{
now = tr[now].next[ch[i] - 'A'];
if (now == 0)
{
++ans;
now = tr[now].next[ch[i] - 'A'];
if (now == 0)
return -1;
}
}
return ans;
}
};
SAM sam;
int n;
char str[500001];
int main()
{
ss(str);
sam.init();
int len = strlen(str);
rep(i, 0, len - 1)
sam.add(str[i]);
sd(n);
while (n--)
{
ss(str);
len = strlen(str);
pd(sam.getAns(str, len));
}
return 0;
}