bzoj4566: [Haoi2016]找相同字符
阿新 • • 發佈:2018-12-02
sam std dep struct mem cst insert ++ str
一個串建SAM,一個串在上面跑DP
需要註意,走到當前節點的時候,有可能走的是近路,並不能把當前節點表示的所有子串匹配,這個時候就要記錄一下走的步數(類似caioj那題),那些被當前點表示的,長度不超過步數的子串才有資格更新答案。
這個東西我用g來維護
然後他去更新其他人就沒有這個限制了,用h表示覆蓋的次數,減去f表示直接走到的次數,然後乘上這個點代表的子串數和出現次數,就是其他人更新我的答案
g和這個東西加起來就是答案了
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; int a[210000],len; struct SAM { int w[30],dep,fail; }ch[410000];int last,cnt; void insert(int dep,int x) { int pre=last,now=++cnt; ch[now].dep=dep; last=now; while(pre!=0&&ch[pre].w[x]==0) ch[pre].w[x]=now, pre=ch[pre].fail; if(pre==0)ch[now].fail=1; else { int nxt=ch[pre].w[x]; if(ch[nxt].dep==ch[pre].dep+1)ch[now].fail=nxt; else { int nnxt=++cnt; ch[nnxt]=ch[nxt]; ch[nnxt].dep=ch[pre].dep+1; ch[nxt].fail=ch[now].fail=nnxt; while(pre!=0&&ch[pre].w[x]==nxt) ch[pre].w[x]=nnxt, pre=ch[pre].fail; } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~init~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int T,Right[410000];//根到當前節點組成的子串(當前節點管理的子串)出現次數,當前節點管理的子串數=ch[x].dep-ch[ch[x].fail].dep int Rsort[410000],sa[410000]; void GetRight() { memset(Rsort,0,sizeof(Rsort)); for(int i=1;i<=cnt;i++)Rsort[ch[i].dep]++; for(int i=1;i<=len;i++)Rsort[i]+=Rsort[i-1]; for(int i=cnt;i>=1;i--)sa[Rsort[ch[i].dep]--]=i; int now=1; memset(Right,0,sizeof(Right)); for(int i=1;i<=len;i++) now=ch[now].w[a[i]], Right[now]++; for(int i=cnt;i>=1;i--) { int u=sa[i],v=ch[u].fail; Right[v]+=Right[u]; } Right[1]=0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //------------------------------------------------------SAM----------------------------------------------------------------- LL f[410000],g[410000],h[410000]; void solve() { int now=1,L=0; memset(f,0,sizeof(f)); memset(g,0,sizeof(g)); memset(h,0,sizeof(h)); for(int i=1;i<=len;i++) { int x=a[i]; while(now!=1&&ch[now].w[x]==0) now=ch[now].fail, L=ch[now].dep; if(ch[now].w[x]!=0) { L++; now=ch[now].w[x]; f[now]++,h[now]++; g[now]+=Right[now]*(L-ch[ch[now].fail].dep); } } for(int i=cnt;i>=1;i--) { int u=sa[i],v=ch[u].fail; f[v]+=f[u]; } LL ans=0; for(int i=2;i<=cnt;i++)ans+=g[i]+(f[i]-h[i])*Right[i]*(ch[i].dep-ch[ch[i].fail].dep); printf("%lld\n",ans); } char ss[210000]; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%s",ss+1);len=strlen(ss+1); last=cnt=1; ch[1].dep=0; for(int i=1;i<=len;i++) a[i]=ss[i]-‘a‘+1, insert(i,a[i]); GetRight(); scanf("%s",ss+1);len=strlen(ss+1); for(int i=1;i<=len;i++)a[i]=ss[i]-‘a‘+1; solve(); return 0; }
bzoj4566: [Haoi2016]找相同字符