表示蒟蒻在ac这道题之前理解的矩乘都是极为片面的
原本我以为矩乘只能优化线性转移,例如f[n]=ai*f[i]+aj*f[j]+ak*f[k].......
其实这样的方程也是可以转移的:f[n]=min(f[i]+ai,f[j]+aj,f[k]+ak......)
Matrix operator *(const Matrix &x)const{ Matrix ret; for (int i=1;i<=n;i++) for (int j=1;j<=n;j++){ ret.a[i][j]=100000000; ret.a[i][j]*=ret.a[i][j]; for (int k=1;k<=n;k++) ret.a[i][j]=min(ret.a[i][j],a[i][k]+x.a[k][j]); } return ret; }
“ You can assume that no hamster's name occurs (as a contiguous fragment) in any other hamster's name. ”
(保证名字互不包含)
这是矩乘的前提保证,翻译太有良心了。。。(在这边被卡了好久。。。)
老样子,代码比较慢比较丑
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int Maxn=100005; char C[Maxn],S[Maxn],ch; int next[Maxn],a[Maxn],len[205],q[Maxn],fl[Maxn]; int num[205],Dis[Maxn],n,m,l,r,i,j,k,tot; LL ans; struct Matrix { LL a[205][205]; Matrix operator *(const Matrix &x)const{ Matrix ret; for (int i=1;i<=n;i++) for (int j=1;j<=n;j++){ ret.a[i][j]=100000000; ret.a[i][j]*=ret.a[i][j]; for (int k=1;k<=n;k++) ret.a[i][j]=min(ret.a[i][j],a[i][k]+x.a[k][j]); } return ret; } } A, B; void add(int x,char ch){ C[++tot]=ch; next[tot]=a[x]; a[x]=tot; } int Judge(int x,char ch){ for (int i=a[x];i;i=next[i]) if (ch==C[i]) return i; return 0; } void ins(int x){ scanf("%s",S); len[x]=strlen(S); int i,j; for (i=0,j=0;i<len[x];i++) if (Judge(j,S[i])) j=Judge(j,S[i]); else add(j,S[i]), j=tot; num[x]=j; for (i=0;i<len[x];i++) fl[i]=-1; for (i=1,j=-1;i<len[x];i++){ while (j>=0 && S[j+1]!=S[i]) j=fl[j]; if (S[j+1]==S[i]) j++; fl[i]=j; } A.a[x][x]=len[x]-j-1; } void AC_Auto(){ for (q[l=r=1]=0;l<=r;l++){ for (i=a[q[l]];i;i=next[i]) q[++r]=i; if (q[l]==0) continue; for (i=a[q[l]];i;i=next[i]){ int x=fl[q[l]]; while (x!=0 && !Judge(x,C[i])) x=fl[x]; fl[i]=Judge(x,C[i]); } } for (i=1;i<=n;i++){ memset(Dis,127/2,sizeof(Dis)); for (j=num[i],r=0;j>0;j=fl[j]) Dis[q[++r]=j]=0; Dis[q[++r]=0]=0; for (l=1;l<=r;l++){ for (j=a[q[l]];j;j=next[j]) for (k=j;k>0;k=fl[k]) if (Dis[k]<=Dis[q[l]]+1) break; else Dis[q[++r]=k] = Dis[q[l]]+1; } for (j=1;j<=n;j++) if (i!=j) A.a[i][j]=Dis[num[j]]; } } void qck(int q){ for (i=1;i<=n;i++) for (j=1;j<=n;j++) if (i!=j) B.a[i][j]=ans; else B.a[i][j]=len[i]; for (;q>0;q>>=1){ if (q&1) B=B*A; A = A * A; } } int main(){ freopen("cho.in","r",stdin); freopen("cho.out","w",stdout); scanf("%d%d\n",&n,&m); memset(A.a,100,sizeof(A.a)); for (i=1;i<=n;i++) ins(i); AC_Auto(); ans=1000000000; ans=ans*ans; qck(m-1); for (i=1;i<=n;i++) for (j=1;j<=n;j++) ans=min(ans,B.a[i][j]); printf("%If4d\n",ans); return 0; }