BZOJ2911 : [Poi1997]The Number of Symmetrical Choices
新建源汇S,T,根据题意可以建出一个DAG
设f[x][y]为从x走到y的回文路径的方案数,则
边界条件:
f[x][x]=1
对于一条边x->y,若a[x]==a[y],则f[x][y]=1
转移方程为:
若a[x]==a[y],则f[x][y]=sum(f[i][j])(x->i有边,j->y有边)
若a[x]!=a[y],则f[x][y]=0
最终答案即为f[S][T],时间复杂度$O(L^2)$。
#include<cstdio> #include<cstring> #define N 410 int n,m,i,j,k,l,a[N],st[2][N],en[2][N],v[N][N],f[N][N];char s[N]; struct E{int v;E*nxt;}*g[N],*h[N],pool[2000],*cur=pool; inline void add(int x,int y){ E*p=cur++;p->v=y;p->nxt=g[x];g[x]=p; p=cur++;p->v=x;p->nxt=h[y];h[y]=p; } int F(int x,int y){ if(v[x][y])return f[x][y]; v[x][y]=1; if(a[x]!=a[y])return 0; for(E*p=g[x];p;p=p->nxt)for(E*q=h[y];q;q=q->nxt)f[x][y]+=F(p->v,q->v); return f[x][y]; } int main(){ scanf("%d",&n),m=2; for(k=0;k<2;k++)for(i=1;i<=n;i++){ st[k][i]=m+1; for(scanf("%s",s+1),l=std::strlen(s+1),j=1;j<l;j++)add(m+j,m+j+1); for(j=1;j<=l;j++)a[m+j]=s[j]-'a'+1; en[k][i]=m+=l; } for(i=1;i<n;i++){ add(en[0][i],st[0][i+1]); add(en[0][i],st[1][i+1]); add(en[1][i],st[0][i+1]); add(en[1][i],st[1][i+1]); } add(1,st[0][1]); add(1,st[1][1]); add(en[0][n],2); add(en[1][n],2); for(i=1;i<=m;i++){ v[i][i]=f[i][i]=1; for(E*p=g[i];p;p=p->nxt){ v[i][p->v]=1; if(a[i]==a[p->v])f[i][p->v]=1; } } return printf("%d",F(1,2)),0; }