设f[i][j]表示串ij可以由哪些字母成长过来,用二进制压位表示。
设g[i][j]表示给定串中[i,j]这个区间一开始可以由哪些字母成长多来,用二进制压位表示。
设h[i]表示给定串前i位最少需要几个字母,h[i]=min(h[j]+1),j<i且[j+1,i]可以由S成长过来。
时间复杂度$O(n^3)$。
#include<cstdio> #include<cstring> #define N 105 int T,n,i,j,k,f[26][26],g[N][N],h[N];char a[N]; inline int cal(int U,int y){ int t=0; for(;U;U-=U&-U)for(int i=__builtin_ctz(U&-U),V=y;V;V-=V&-V)t|=f[i][__builtin_ctz(V&-V)]; return t; } int main(){ for(scanf("%d",&n);n--;f[a[1]-'A'][a[2]-'A']|=1<<(a[0]-'A'))scanf("%s",a); for(scanf("%d",&T);T--;){ for(scanf("%s",a+1),n=std::strlen(a+1),i=1;i<=n;i++)a[i]-='A'; for(i=n;i;i--)for(g[i][i]=1<<a[i],j=i+1;j<=n;j++)for(g[i][j]=0,k=i;k<j;k++)g[i][j]|=cal(g[i][k],g[k+1][j]); for(i=1;i<=n;i++)for(h[i]=N,j=0;j<i;j++)if((g[j+1][i]&262144)&&h[j]+1<h[i])h[i]=h[j]+1; if(h[n]<N)printf("%d ",h[n]);else puts("NIE"); } return 0; }