 /**//*
题意:对于DFA,F(u,c)表示u在输入c后跳到状态F(u,c)
该DFA有K个状态,给出起点S,还有T个终点和状态转移函数F(u,c)
问S到T路径长度为N的路径条数
不过F(u,c)有些特殊,如果边G[u,c]=1表示从u转到F(u,c)后,
接下来要用的字母还是c,不是下一个字母

对于普通的DFA,求从起点到终点的路径条数可以用DP
dp[n,pos]表示长度为n,从起点到pos的路径条数
dp[n,pos]+=dp[n-1,pos'] , pos'->pos
初始dp[0,1]=1
先用dfs处理掉那些特殊边,然后就是普通的DFA了
在某点沿某条边出发,如果有G(u,c)=1的环,说明永远不会accept,
否则我们就将这条边指向第一个G(u,c)=0处(E[pos][ch]=dfs(E[pos][ch]))
*/
#include<cstdio>
#include<cstring>

typedef long long LL;
const int ml=100,base=100000000,nd=8;
int n,m,k,i,j;
 struct bign { int len,s[ml]; };
 void print(bign &bi) {
printf("%d",bi.s[bi.len]);
for(int i=bi.len-1;i;i--)printf("%08d",bi.s[i]);
}
 void fixlen(bign &bi) { while(bi.len>1 && !bi.s[bi.len])bi.len--; }
 void init(bign &bi) { bi.len=1; memset(bi.s,0,sizeof(bi.s)); }
 void init(bign &bi,int a) {
init(bi);
 while(a) { bi.s[bi.len++]=a%base; a/=base; }
bi.len--;
}
 int cmp(bign &a,bign &b) {
if( a.len != b.len ) return a.len-b.len;
for(int i=a.len;i;i--)if(a.s[i] != b.s[i]) return a.s[i]-b.s[i];
return 0;
}
 bign operator+(bign &a,bign &b) {
bign c; int i; init(c);
 for(i=1;i<=a.len || i<=b.len || c.s[i];i++) {
c.s[i]+=a.s[i]+b.s[i];
c.s[i+1]=c.s[i]/base; c.s[i]%=base;
}
if(i>1)c.len=i-1;else c.len=1;
return c;
}

bool G[1001][27];
int F[1001][27],E[1001][27];//F原来的 E新建的
int Ta[1001];
int K,N,Z,S,TNum;
bign dp[2][1001],ZERO;

 /**//*dfs是抄的 */
int dfs(int pos,int ch)//check char for all pos -1 for cycle , 0 for not check
  {
if(E[pos][ch]!=-1)
 {
if(!G[pos][ch])//ok
E[pos][ch]=F[pos][ch];
else
 {
E[pos][ch]=-1;
E[pos][ch]=dfs(F[pos][ch],ch);//
}
}
return E[pos][ch];
}

int main()
  {
// freopen("in","r",stdin);
init(ZERO);
int T;
scanf("%d",&T);
while(T--)
 {
char str[30];
scanf("%s",str);Z=strlen(str);
scanf("%d%d%d",&K,&S,&TNum);
for(int i=0;i<TNum;i++)scanf("%d",&Ta[i]);
for(int i=1;i<=K;i++)
for(int j=1;j<=Z;j++)
scanf("%d",&F[i][j]);
memset(E,0,sizeof(E));//新边,0表示还未定
for(int i=1;i<=K;i++)
for(int j=1;j<=Z;j++)
scanf("%d",&G[i][j]);
for(int j=1;j<=Z;j++)
for(int i=1;i<=K;i++)
if(!E[i][j])dfs(i,j);
scanf("%d",&N);
for(int i=1;i<=K;i++)init(dp[0][i]);
init(dp[0][S],1);//S not 1
for(int n=1;n<=N;n++)
 {
for(int i=1;i<=K;i++)init(dp[n&1][i]);
for(int i=1;i<=K;i++)
 {
if(cmp(dp[(n-1)&1][i],ZERO)==0)continue;
for(int j=1;j<=Z;j++)
if(E[i][j]>0)dp[n&1][E[i][j]]=dp[n&1][E[i][j]]+dp[(n-1)&1][i];
}
}
bign ans;
init(ans);
for(int i=0;i<TNum;i++)
ans=ans+dp[N&1][Ta[i]];
print(ans);
puts("");
if(T)puts("");
}
return 0;
}
|
|
常用链接
随笔分类
Links
搜索
最新评论

|
|