POJ-1625 & ZOJ-1540 & Ural-1158 AC自动机+DP+大数..

      AC自动机的DP...每个节点是状态..每条边是转移方向..其实这题和 POJ-2778 DNA Sequence  是一回事..只是这题是高精度..并且数据范围没那么大..所以使得直接DP的效率从时间和空间上都远远高于了用矩阵乘法...囧..

      其实准确的说这题所构造的图不是AC自动机而是Trie图...为了DP转移时更加方便..把节点没有的孩子赋值为其fail点的这个孩子...这样在DP时就不用考虑fail了..直接枚举每个点来通过这个点的有向边更新其他点...

      DP时很明显每一次都只于前一次有关...所以可以用滚动数组来存点的dp值..

      DP转移方程为:

                   v[k][x]+=v[1-k][h];      (k做滚动数组标记的..h是有向线段的起点..x是有向线段的终点) 

      这题很显然要用高精度了..因为是这样的转移关系..所以只要考虑在做加法的时候会不会爆..我是每位存8个十进制数...效率确实很好....

      这题非常要小心的一个是对带病毒点的处理...还有就是对结果是0的处理...我就是处理得不彻底结果WA了N久....

             


我的一些测试数据(也贴在POJ-1625的Discuss了..):

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



Program:

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<queue> 
#define uchar unsigned char
#define N 55
using namespace std;
struct node1
{
     int son[55],fail;
     bool w;
}point[202]; 
int n,m,p,v[2][202][N+2],g[606];
char s[105];
bool used[202];
queue<int> myqueue;  
int main()
{ 
     freopen("input.txt","r",stdin);
     freopen("output.txt","w",stdout);
     int i,l,a[N+2],num,h,k;
     scanf("%d%d%d\n",&n,&m,&p); 
     gets(s);   l=strlen(s);
     memset(g,0,sizeof(g));
     for (i=0;i<l;i++) g[s[i]+128]=i;
     memset(point,0,sizeof(point));
     num=0;
     while (p--)
     {
           gets(s);
           l=strlen(s);
           h=0;
           for (i=0;i<l;i++)
           { 
                 k=g[s[i]+128];
                 if (!point[h].son[k])
                 {
                        num++;
                        point[h].son[k]=num;
                 }
                 h=point[h].son[k];
                 if (point[h].w) break;
           }
           point[h].w=true; 
     }
     while (!myqueue.empty()) myqueue.pop();
     memset(v,0,sizeof(v));
     for (i=0;i<n;i++)
         if (point[0].son[i]) 
         {
                myqueue.push(point[0].son[i]);
                if (!point[point[0].son[i]].w)
                   v[0][point[0].son[i]][0]++;
         }else v[0][0][0]++;
     while (!myqueue.empty())
     {
           h=myqueue.front();
           myqueue.pop();
           if (point[point[h].fail].w) point[h].w=true;
           if (point[h].w) continue;
           for (i=0;i<n;i++) 
           {
                 k=point[h].fail; 
                 while (k && !point[k].son[i]) k=point[k].fail; 
                 point[point[h].son[i]].fail=point[k].son[i];
                 if (!point[h].son[i])
                    point[h].son[i]=point[k].son[i];
                 else
                    myqueue.push(point[h].son[i]);
           }
     } 
     k=0;
     m--;
     while (m--)
     { 
           k=1-k;
           memset(v[k],0,sizeof(v[k]));
           memset(used,false,sizeof(used));
           used[0]=true;
           myqueue.push(0);
           while (!myqueue.empty())
           {
                  h=myqueue.front();
                  myqueue.pop();
                  if (point[h].w) continue;
                  for (i=0;i<n;i++)
                  if (!point[point[h].son[i]].w)
                  {
                        if (!used[point[h].son[i]])
                        {
                             myqueue.push(point[h].son[i]);
                             used[point[h].son[i]]=true;
                        }
                        for (p=0;p<N;p++)
                        { 
                             v[k][point[h].son[i]][p]+=v[1-k][h][p];
                             if (v[k][point[h].son[i]][p]>99999999)
                             {
                                  v[k][point[h].son[i]][p+1]+=v[k][point[h].son[i]][p]/100000000;
                                  v[k][point[h].son[i]][p]%=100000000;
                             } 
                        }
                  }
           }
     }  
     memset(a,0,sizeof(a));
     for (i=0;i<=num;i++)
        for (p=0;p<N;p++)
        { 
              a[p]+=v[k][i][p];
              if (a[p]>99999999)
              {
                    a[p+1]+=a[p]/100000000;
                    a[p]%=100000000;
              } 
        }
     for (p=N;p>=0;p--)
        if (a[p]) break;
     if (p==-1) p=0;
     printf("%d",a[p]);
     p--;
     for (;p>=0;p--)
     { 
            if (a[p]<10000000 ) printf("0");
            if (a[p]<1000000  ) printf("0");
            if (a[p]<100000   ) printf("0");
            if (a[p]<10000    ) printf("0");
            if (a[p]<1000     ) printf("0");
            if (a[p]<100      ) printf("0");
            if (a[p]<10       ) printf("0");
            printf("%d",a[p]);
     }
     printf("\n"); 
     return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值