【[USACO17DEC]Standing Out from the Herd】
阿新 • • 發佈:2019-01-10
不會廣義\(SAM\)啊
但信仰插入特殊字元就可以搞定一切了
我們先把所有的串搞在一起建出一個\(SAM\),記得在中間插入特殊字元
對於\(parent\)樹上的一個節點,只有當其\(endpos\)集合中的所有元素都來自於同一個串的時候我們才對它進行統計
所以我們需要維護一個\(parent\)樹上子樹最大值和最小值,這樣我們就能很快的判斷這個\(endpos\)是否合法了
但是非常棘手的一類情況是我們插進去的特殊字元,顯然\(SAM\)裡有一些奇奇怪怪的子串中含有特殊字元
那也好辦,我們存好每個串的起始位置只要那些沒有跨越特殊字元的就好了
#include<iostream> #include<cstring> #include<cstdio> #define maxn 200005 #define re register #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) struct E{int v,nxt;} e[maxn]; char S[maxn]; int m,n,lst=1,cnt=1,num; int len[maxn],fa[maxn],son[maxn][27],mx[maxn],ml[maxn]; int f[maxn],head[maxn],d[maxn],Ans[maxn],li[maxn]; inline void add(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;} void dfs(int x) { for(re int i=head[x];i;i=e[i].nxt) dfs(e[i].v),mx[x]=max(mx[e[i].v],mx[x]),ml[x]=min(ml[e[i].v],ml[x]),d[x]|=d[e[i].v]; } inline void ins(int c,int o) { int f=lst,p=++cnt; lst=p; len[p]=len[f]+1,mx[p]=ml[p]=o; if(c==26) d[p]=1; while(f&&!son[f][c]) son[f][c]=p,f=fa[f]; if(!f) {fa[p]=1;return;} int x=son[f][c]; if(len[f]+1==len[x]) {fa[p]=x;return;} int y=++cnt; len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y; for(re int i=0;i<27;i++) son[y][i]=son[x][i]; while(f&&son[f][c]==x) son[f][c]=y,f=fa[f]; } int main() { memset(ml,20,sizeof(ml)); scanf("%d",&m); for(re int i=1;i<=m;i++) { scanf("%s",S+1); int len=strlen(S+1);li[i]=n+1; for(re int j=1;j<=len;j++) ins(S[j]-'a',++n),f[n]=i; ins(26,++n); } for(re int i=2;i<=cnt;i++) add(fa[i],i); dfs(1); for(re int i=2;i<=cnt;i++) { if(d[i]) continue; if(f[mx[i]]!=f[ml[i]]) continue; int minlen=len[fa[i]]+1; if(f[mx[i]-minlen+1]!=f[mx[i]]) continue; if(f[mx[i]-len[i]+1]==f[mx[i]]) Ans[f[mx[i]]]+=len[i]-len[fa[i]]; else Ans[f[mx[i]]]+=mx[i]-li[f[mx[i]]]-minlen+2; } for(re int i=1;i<=m;i++) printf("%d\n",Ans[i]); return 0; }