poj 2778 AC自动机DP

从AC了poj1625 censored!一题后,又解决了一道AC自动机DP题。

【题意】

同poj 1625

【题解】

poj 1625是dp,而这道题的DP通过矩阵实现。

【代码】

#include <iostream>
#include <queue>
using namespace std;
const int maxn=100,base=100000,kind=4;

struct node
{
       int sum,id;
       node* ch[kind];
       node* fail;
}a[maxn];
int ans[maxn][maxn],f[maxn][maxn];
int tot=0,m,n;

node* getroot()
{
      tot++;
      int i;
      for (i=0;i<kind;i++)
          a[tot].ch[i]=0;
      a[tot].fail=0;
      a[tot].id=tot;
      a[tot].sum=0;
      return &a[tot];
}
node* root=getroot();

node* getnode()
{
      tot++;
      int i;
      for (i=0;i<kind;i++)
          a[tot].ch[i]=0;
      a[tot].fail=root;
      a[tot].id=tot;
      a[tot].sum=0;
      return &a[tot];
}

void ins(char* s)
{
     int i,k,len=strlen(s);
     node* now=root;
     for (i=0;i<len;i++)
     {
         if (s[i]=='A') k=0;
         if (s[i]=='C') k=1;
         if (s[i]=='T') k=2;
         if (s[i]=='G') k=3;
         if (now->ch[k]==0)
            now->ch[k]=getnode();
         now=now->ch[k];
     }
     now->sum++;
}
 
queue<node*> q;
void build()
{
     int i,k;
     node* now,*ff;
     q.push(root);
     while (!q.empty())
     {
           now=q.front();
           q.pop();
           for (i=0;i<kind;i++)
               if (now->ch[i]!=0)
               {
                  q.push(now->ch[i]);
                  for (ff=now->fail;ff!=0;ff=ff->fail)
                      if (ff->ch[i]!=0)
                      {
                         now->ch[i]->fail=ff->ch[i];
                         if (ff->ch[i]->sum==1) now->ch[i]->sum=1;//很重要
                         break;
                      }
               }
     }
}

void init()
{
     cin >> m >> n;
     int i;
     char s[maxn];
     for (i=1;i<=m;i++)
     {
         cin >> s;
         ins(s);
     }
}

void get_matrix()
{
     node* now,*tmp;
     int i,j,ct;
     for (i=1;i<=tot;i++)
         for (j=0;j<kind;j++)
         {
             now=&a[i];
             if (now->ch[j]!=0)
             {
                ct=now->ch[j]->id;
                if (now->ch[j]->sum==0) f[ct][i]++;
             }
             else
             {
                 for (tmp=now->fail;tmp!=0;tmp=tmp->fail)
                     if (tmp->ch[j]!=0)
                        break;
                 if (tmp!=0) tmp=tmp->ch[j];
                 else tmp=root;
                 ct=tmp->id;
                 if (tmp->sum==0) f[ct][i]++;
             }
         }
}

void mul(int a[][maxn],int b[][maxn])
{
     int i,j,k;
     int c[maxn][maxn]={0};
     for (i=1;i<=tot;i++)
         for (j=1;j<=tot;j++)
             for (k=1;k<=tot;k++)
             {
                 long long tt=a[i][k];
                 tt=(tt*b[k][j])%base;
                 c[i][j]=(c[i][j]+int(tt))%base;
             }
     for (i=1;i<=tot;i++)
         for (j=1;j<=tot;j++)
             a[i][j]=c[i][j];
}

int cal()
{
     int i,sum;
     for (i=1;i<=tot;i++)
         ans[i][i]=1;
     while (n)
     {
           if (n&1)
              mul(ans,f);
           mul(f,f);
           n>>=1;
     }
     sum=0;
     for (i=1;i<=tot;i++)
         sum+=ans[i][1];
     return sum%base;
}

int main()
{
    freopen("pin.txt","r",stdin);
    freopen("pou.txt","w",stdout);
    init();
    build();
    get_matrix();
    cout << cal() << endl;
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值