考虑同构的性质
对每个字符维护上一次出现在哪个位置,容易发现对于两个串,如果他们同构,那么这两个串的 pre 序列一定是完全一样的。
我们使用类似 SA 求 lcp 的套路,对这个东西做后缀排序。因为每个后缀的 pre 序列不一样,所以只能使用 sort+二分 Hash 然后复杂度就成了 (O(nlog^3n))
虽然理论复杂度是对的,但奈何这个东西的常数实在是太大大大大大了,一组极限数据,本地运行了 23s。
#include<bits/stdc++.h>
using namespace std;
#define u64 unsigned long long
template<typename _T>
inline void read(_T &x)
{
x=0;char s=getchar();int f=1;
while(s<'0'||s>'9') {f=1;if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
x*=f;
}
const u64 base = 131;
const int np = 5e4 + 5;
const int cp = 2 * np + np * 17;
int n,Cnt;
u64 p[np];
int a[np],ver[np],sa[np];
int bac[np];
struct Node{
Node *ls,*rs;
u64 Val;
}mem[cp],*pool = mem,*rot[np];
inline Node *New(){
++pool;
pool->ls = pool->rs=0;
pool->Val = 0;
return pool;
}
inline Node *build(int L,int R)
{
Node *u = New();
if(L == R){
u->ls = u->rs = 0;
u->Val = 0;
}
else{
int mid = L + R >> 1;
u->ls = build(L,mid);
u->rs = build(mid+1,R);
}
return u;
}
inline void upd(Node *u,Node *pr,int l,int r,int pos,int x)
{
*u = *pr;
if(l == r){
u->Val = x;
return;
}
int mid = l + r >> 1;
if(pos <= mid) upd(u->ls=New(),pr->ls,l,mid,pos,x);
else upd(u->rs=New(),pr->rs,mid+1,r,pos,x);
u->Val = (u->ls->Val * p[r-mid]) + u->rs->Val;
}
inline u64 query(Node *u,int l,int r,int L,int R)
{
if(L <= l && r <= R){
return u->Val;
}
if(r < L || R < l) return 0;
int mid = l + r >> 1;
if(R <= mid) return query(u->ls,l,mid,L,R);
else if(mid+1 <= L) return query(u->rs,mid+1,r,L,R);
else return query(u->ls,l,mid,L,mid) * p[R-mid] + query(u->rs,mid+1,r,mid+1,R);
}
inline int Lcp(int u,int v)
{
if(u == v) return n-u+1;
if(v < u) swap (u,v);
int l=0,r = n-v,ans(-1);
while(l <= r)
{
int mid = l + r >> 1;
if(query(rot[u],1,n,u,u+mid) == query(rot[v],1,n,v,v+mid)){
l = mid + 1;
ans = mid;
}
else r = mid - 1;
}
return ans+1;
}
inline int Get_(Node *u,int pos)
{
if(pos > n) return -1;
else return query(u,1,n,pos,pos);
}
inline bool cmp(int u,int v)
{
int len = Lcp(u,v);
return Get_(rot[u],u+len) < Get_(rot[v],v+len);
}
inline void Clr()
{
for(int i=1;i <= n;i ++) bac[i] = 0,rot[i] = 0;
pool = mem;
}
signed main()
{
int V = 5e4;
p[0] = 1;
for(int i=1;i <= V; i ++) p[i] = p[i-1] * base;
while(Clr(),scanf("%d",&n)!=EOF)
{
for(int i=1;i <= n;i ++) read(a[i]);
rot[n] = build(1,n);
bac[a[n]] = n;
for(int i=n-1;i >= 1;i --)
{
if(bac[a[i]]) upd(rot[i]=New(),rot[i + 1],1,n,bac[a[i]],bac[a[i]]-i);
else rot[i] = rot[i + 1];
bac[a[i]]=i;
}
for(int i=1;i <= n;i ++) sa[i] = i;
sort(sa + 1,sa + 1 + n,cmp);
u64 Ans = 1ull * n * (n + 1)/2;
for(int i=2;i <= n;i ++) Ans -= Lcp(sa[i],sa[i-1]);
printf("%llu
",Ans);
}
}
贴上这份只能得 (60pts) 的代码