poj 1625 AC自动机上的DP_codestorm_新浪博客

本文详细介绍了使用AC自动机解决给定字符集合与禁用字符串组合的问题,通过定义状态转移矩阵并进行DP计算,最终得出长度为M的合法字符串个数。文中提供了解题思路与实现代码,包括初始化自动机、构建状态转移图及DP算法的运用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:http://blog.youkuaiyun.com/ascii991/article/details/7462427


【题意】

给定N个字符集合和P个禁用的字符串,求长度为M的合法字符串个数。

【题解】

显然是AC自动机上的DP。

令dp[i][j]表示长度为i,状态为j的字符串个数。

按自动机的图转移即可,但要注意细节。

 

贡献几组数据。

 

50 50 10
qwertyuiop[]\asdfghjkl;'zxcvbnm,./ QWERTYUIOP{}|AS
aegaegu
etoijqt
tquqi
witowwt
zxcjnc
oeit
potieq
iojge
nvoq
piqper

ans=8881647922834867244791415981705771412427494861672253136057167374729235842468240763290

1 1 1
a
a

ans=0

5 10 3
abcde
abc
bc
c

ans=1048576

  1. #include   
  2. #include   
  3. using namespace std;  
  4. const int maxn=800,maxm=55,base=100000000,kind=55;  
  5.   
  6. struct node  
  7. {  
  8.        int sum,id;  
  9.        node* ch[kind];  
  10.        node* fail;  
  11. }a[maxn];  
  12.   
  13. struct num  
  14. {  
  15.        int g[20];  
  16.        int len;  
  17.        num()  
  18.        {  
  19.             memset(g,0,sizeof(g));  
  20.             len=1;  
  21.        }  
  22. }dp[maxm][maxn];  
  23.   
  24. char s[maxm];  
  25. int dx[400];  
  26. int n,m,p,tot=0;  
  27.   
  28. node* getroot()  
  29. {  
  30.       tot++;  
  31.       int i;  
  32.       for (i=0;i
  33.           a[tot].ch[i]=0;  
  34.       a[tot].fail=0;  
  35.       a[tot].id=tot;  
  36.       a[tot].sum=0;  
  37.       return &a[tot];  
  38. }  
  39. node* root=getroot();  
  40.   
  41. node* getnode()  
  42. {  
  43.       tot++;  
  44.       int i;  
  45.       for (i=0;i
  46.           a[tot].ch[i]=0;  
  47.       a[tot].fail=root;  
  48.       a[tot].id=tot;  
  49.       a[tot].sum=0;  
  50.       return &a[tot];  
  51. }  
  52.   
  53. void ins(char* s)  
  54. {  
  55.      int i,k,len=strlen(s);  
  56.      node* now=root;  
  57.      for (i=0;i
  58.      {  
  59.          k=dx[s[i]+128];  
  60.          if (now->ch[k]==0)  
  61.             now->ch[k]=getnode();  
  62.          now=now->ch[k];  
  63.      }  
  64.      now->sum++;  
  65. }  
  66.    
  67. void init()  
  68. {  
  69.      int i;  
  70.      char st[maxm];  
  71.      scanf("%d%d%d\n",&n,&m,&p);  
  72.      gets(s);  
  73.      for (i=0;i
  74.          dx[s[i]+128]=i;  
  75.      for (i=1;i<=p;i++)  
  76.      {  
  77.          scanf("%s",st);  
  78.          ins(st);  
  79.      }  
  80. }  
  81.   
  82. queue q;  
  83. void build()  
  84. {  
  85.      int i,k;  
  86.      node* now,*ff;  
  87.      q.push(root);  
  88.      while (!q.empty())  
  89.      {  
  90.            now=q.front();  
  91.            q.pop();  
  92.            for (i=0;i
  93.                if (now->ch[i]!=0)  
  94.                {  
  95.                   q.push(now->ch[i]);  
  96.                   for (ff=now->fail;ff!=0;ff=ff->fail)  
  97.                       if (ff->ch[i]!=0)  
  98.                       {  
  99.                          now->ch[i]->fail=ff->ch[i];  
  100.                          if (ff->ch[i]->sum==1) now->ch[i]->sum=1;  
  101.                          break;  
  102.                       }  
  103.                }  
  104.      }  
  105. }  
  106.   
  107. num operator +(num a,num b)  
  108. {  
  109.     num c=num();  
  110.     int i,t,k=0,len=max(a.len,b.len);  
  111.     for (i=1;i<=len;i++)  
  112.     {  
  113.         t=a.g[i]+b.g[i]+k;  
  114.         k=t/base;  
  115.         c.g[i]=t�se;  
  116.     }  
  117.     while (k)  
  118.     {  
  119.           c.g[++len]=k�se;  
  120.           k/=base;  
  121.     }  
  122.     c.len=len;  
  123.     return c;  
  124. }  
  125.   
  126. void DP()  
  127. {  
  128.      int i,j,k;  
  129.      dp[0][1].g[1]=1;  
  130.      for (i=0;i
  131.          for (j=1;j<=tot;j++)  
  132.          {  
  133.              node* now=&a[j];  
  134.              for (k=0;k
  135.                  if (now->ch[k]!=0)  
  136.                  {  
  137.                     int ct=now->ch[k]->id;  
  138.                     if (now->ch[k]->sum==0) dp[i+1][ct]=dp[i+1][ct]+dp[i][j];  
  139.                  }  
  140.                  else  
  141.                  {  
  142.                      node* tmp=now->fail;  
  143.                      for (;tmp!=0;tmp=tmp->fail)  
  144.                          if (tmp->ch[k]!=0)  
  145.                          {  
  146.                             tmp=tmp->ch[k];  
  147.                             break;  
  148.                          }  
  149.                      if (tmp==0) tmp=root;  
  150.                      int ct=tmp->id;  
  151.                      if (tmp->sum==0) dp[i+1][ct]=dp[i+1][ct]+dp[i][j];  
  152.                  }  
  153.          }  
  154. }  
  155.   
  156. void print()  
  157. {  
  158.      int i,j;  
  159.      num ans=num();  
  160.      for (i=1;i<=tot;i++)  
  161.          ans=ans+dp[m][i];  
  162.      j=ans.len;  
  163.      printf("%d",ans.g[j]);  
  164.      for (i=j-1;i>=1;i--)  
  165.      {  
  166.          if (ans.g[i]"0");  
  167.          if (ans.g[i]"0");  
  168.          if (ans.g[i]"0");  
  169.          if (ans.g[i]"0");  
  170.          if (ans.g[i]"0");  
  171.          if (ans.g[i]"0");  
  172.          if (ans.g[i]"0");  
  173.          printf("%d",ans.g[i]);  
  174.      }  
  175.      printf("\n");  
  176. }  
  177.   
  178. int main()  
  179. {  
  180.     freopen("pin.txt","r",stdin);  
  181.     freopen("pou.txt","w",stdout);  
  182.     init();  
  183.     build();  
  184.     DP();  
  185.     print();  
  186.     return 0;  
  187. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值