2020牛客多校第八场 H Hard String Problem(广义后缀自动机)
取最小循环节的最小表示法的字符串,翻若干倍插入广义后缀自动机,最后用树状数组统计parent树上子树包含所有串的节点所代表的字符串的个数,累加即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const int N = 2e6 + 5;
const int maxn = 300010;
ll ans;
int n;
struct QU { int id,l,r; };
struct Suffix_Automaton
{
QU qry[N];
int c[N], ans[N];
int O, ru[N], link[N], maxlen[N], trans[N][26];
vector<int>g[N],siz[N];
int in[N],out[N],tim=0;
int Q[N],head,tail;
void add(int p,int v) { for(; p <= O; p += p&(-p)) c[p] += v; }
int query(int p) { int ret = 0; for(; p; p -= p&(-p)) ret += c[p]; return ret; }
Suffix_Automaton() { O = 1; }
int insert(int ch, int last, int id)
{
if (trans[last][ch])
{
int p = last, x = trans[p][ch];
if (maxlen[p] + 1 == maxlen[x])
{
siz[x].push_back(id);
return x;
}
else
{
int y = ++O;
maxlen[y] = maxlen[p] + 1;
for (int i = 0; i < 26; ++i)
trans[y][i] = trans[x][i];
while (p && trans[p][ch] == x)
trans[p][ch] = y, p = link[p];
link[y] = link[x], link[x] = y;
siz[y].push_back(id);
return y;
}
}
int z = ++O, p = last;
maxlen[z] = maxlen[last] + 1;
while (p && !trans[p][ch])
trans[p][ch] = z, p = link[p];
if (!p)
link[z] = 1;
else
{
int x = trans[p][ch];
if (maxlen[p] + 1 == maxlen[x])
link[z] = x;
else
{
int y = ++O;
maxlen[y] = maxlen[p] + 1;
for (int i = 0; i < 26; ++i)
trans[y][i] = trans[x][i];
while (p && trans[p][ch] == x)
trans[p][ch] = y, p = link[p];
link[y] = link[x], link[z] = link[x] = y;
}
}
siz[z].push_back(id);
return z;
}
void init()
{
for(int i=2;i<=O;i++){
g[link[i]].push_back(i);
}
}
int num[N];
void dfs(int x,int fa){
in[x]=++tim;
num[tim]=x;
for(auto i:g[x]){
if(fa==i)continue;
dfs(i,x);
}
out[x]=tim;
qry[x] = {x,in[x],out[x]};
}
int lst[N];
void cal()
{
init();
dfs(1,-1);
int now = 1;
sort(qry+1,qry+1+O,[&](QU x,QU y){ return x.r<y.r; });
for(int i = 1; i <= O; i++){
for(auto x : siz[num[i]]){
if(lst[x]) add(lst[x],-1);
add(i,1),lst[x] = i;
}
while(now<=O&&qry[now].r==i){
ans[qry[now].id] = query(i)-query(qry[now].l-1);
++now;
}
}
ll res = 0;
for(int i = 2; i <= O; i++){
if(ans[i]==n){
res += maxlen[i]-maxlen[link[i]];
}
}
cout<<res<<'\n';
}
} SAM;
int nx[maxn];
int get_loop(string s)
{
int len=s.size();
for(int i=0;i<=len+1;i++)nx[i]=0;
nx[0] = -1;
int i = 0, j = -1;
while (i < len){
if (j == -1 || s[i] == s[j]) nx[++i] = ++j;
else j = nx[j];
}
int now = len-nx[len];
if(len%now==0)return now;
return len;
}
int getMin(string s,int len)
{
int i = 0, j = 1, l;
while(i < len && j < len){
for(l = 0; l < len; l++)
if(s[(i + l) % len] != s[(j + l) % len]) break;
if(l >= len) break;
if(s[(i + l) % len] > s[(j + l) % len]){
if(i + l + 1 > j) i = i + l + 1;
else i = j + 1;
}
else if(j + l + 1 > i) j = j + l + 1;
else j = i + 1;
}
return i < j ? i : j;
}
string s[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
ans = 0;
for(int i=0;i<n;i++)
{
cin>>s[i];
int ml=get_loop(s[i]);
int idx=getMin(s[i],ml);
s[i]=s[i].substr(idx,ml-idx)+s[i].substr(0,idx);
}
sort(s,s+n);
n=unique(s,s+n)-s;
if(n==1){
cout<<-1<<'\n';
return 0;
}
int minid = 0, maxid = 0;
for (int i=0;i<n;i++){
if (s[i].length() < s[minid].length()) minid = i;
if (s[i].length() > s[maxid].length()) maxid = i;
}
int len = s[minid].length();
int target = s[maxid].length() * 2;
int cnt=target/len+1;
int last=1;
while(cnt--){
for(int i=0;i<len;i++){
last = SAM.insert(s[minid][i] - 'a', last, minid);
}
}
for(int i=0;i<n;i++){
if(i==minid)continue;
last=1;
for(auto j:s[i]){
last=SAM.insert(j-'a',last,i);
}
for(auto j:s[i]){
last=SAM.insert(j-'a',last,i);
}
}
SAM.cal();
return 0;
}

浙公网安备 33010602011771号