【BZOJ】5233: [Lydsy2017省隊十連測]壞題-AC自動機&縮點
阿新 • • 發佈:2018-12-18
題解
這題難點在讀題上。。。。
經過多番嘗(shi)試(tan),終於明白了兩端均無限長的鏈的意思。
匹配問題首先建顆AC自動機:將所有為字串終止位置的節點及其鏈上的點都標記起來,記為,其餘點。
考慮一個兩端均無限長的鏈中不出現這個串中任意一個,那麼就是在AC自動機上不經過的點上繞環。
將所有的點及其中的點之間連一條指向的有向邊,取出新建的圖,那麼構造出的無限長的串就是這張圖上的一條帶環路徑,每一條不同的路徑代表的串都不同。
首先考慮解無窮多的情況:如果一個點在多個環中,那麼這個點出發就會有任意多種組合。所以答案有限的情況的前提就是這張圖中只有簡單環。
因為圖上只有簡單環,tarjan縮點以後變成DAG,就可以在DAG上拓撲序DP了。
但現在我們只是滿足了答案有限,對於一個兩端均無限長的鏈還需要一個限制條件:這條路徑的起點和終點都是在一個環內。
那麼問題的本質就是求AC自動機中取出的這張圖上起點終點都為的不同路徑數
p.s. 考慮到一種特殊的情況:一條路徑途中也有環,答案似乎就是無限的了。但這種情況根本不存在,它已經在一個點在兩個環中的情況中算到了。
程式碼
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<algorithm> #include<cctype> #include<ctime> #include<queue> #include<cstdlib> #include<vector> #include<map> using namespace std; const int N=1e4+10; int fir,n,ans,cnt,bel[N],inq[N]; int head[N],to[N*6],nxt[N*6],tot; int df[N],low[N],stk[N],dfn,top; int ind[N],dp[N],cir,jud,selc[N],isc[N]; char s[15]; vector<int>hv[N],g[N]; inline void lk(int u,int v) {to[++tot]=v;nxt[tot]=head[u];head[u]=tot;ind[v]++;} struct ACT{ queue<int>que; int len,ch[N][7],f[N],ed[N]; inline void ins() { register int i,j,u=0,alp; scanf("%s",s+1); len=strlen(s+1); for(i=1;i<=len;++i){ alp=s[i]-'a'; if(!ch[u][alp]) ch[u][alp]=++cnt; u=ch[u][alp]; } ed[u]=1; } inline void build() { register int i,j,x,y,z,u; for(i=0;i<fir;++i) if(ch[0][i]) que.push(ch[0][i]); for(;!que.empty();){ x=que.front();que.pop();y=f[x]; for(i=0;i<fir;++i){ z=ch[x][i];u=ch[y][i]; if(!z) {ch[x][i]=u;continue;} f[z]=u;ed[z]|=ed[u];que.push(z); } } } inline void lik() { int i,j,cot=0; for(i=0;i<=cnt;++i) if(!ed[i]){ for(j=0;j<fir;++j) if(!ed[ch[i][j]]){ g[i].push_back(ch[i][j]); if(i==ch[i][j]) selc[i]++; } } } }ac; void dfs(int x) { df[x]=low[x]=++dfn;stk[++top]=x;inq[x]=1; int i,j; for(i=g[x].size()-1;~i;--i){ j=g[x][i]; if(!df[j]){ dfs(j);low[x]=min(low[x],low[j]); }else if(inq[j]) low[x]=min(low[x],df[j]); } if(low[x]==df[x]){ ++cir; for(;stk[top+1]!=x;--top){ i=stk[top]; inq[i]=0;bel[i]=cir; hv[cir].push_back(i); } if(hv[cir].size()==1 && (!selc[x])){ isc[cir]=0; }else isc[cir]=1; } } void ck(int u) { if(jud) return; inq[u]=1; for(int j,i=g[u].size()-1;~i;--i){ j=g[u][i]; if(inq[j]){inq[j]++;if(inq[j]>2) {jud=1;return;}} else{ck(j);if(jud) return;} } inq[u]=0; } queue<int>Q; inline void mkk() { int i,j,k,t,x,y; for(i=1;i<=cir;++i) { for(j=hv[i].size()-1;~j;--j){ k=hv[i][j]; for(x=g[k].size()-1;~x;--x){ y=g[k][x]; if(i!=bel[y]) lk(i,bel[y]); } } } for(i=1;i<=cir;++i) if(!ind[i]) Q.push(i); for(;!Q.empty();){ x=Q.front();Q.pop(); dp[x]+=isc[x]; if(isc[x]) ans+=dp[x]; for(i=head[x];i;i=nxt[i]){ j=to[i];ind[j]--; dp[j]+=dp[x]; if(!ind[j]) Q.push(j); } } printf("%d\n",ans); } int main(){ scanf("%d%d",&fir,&n); for(register int i=1;i<=n;++i) ac.ins(); ac.build();ac.lik(); jud=0;ck(0); if(jud) {puts("-1");return 0;} for(int i=0;i<=cnt;++i) if(!df[i]) dfs(i); mkk(); return 0; }