poj 1625 Censored! (ac自动机+dp)

来源:互联网 发布:怎样学习单片机编程 编辑:程序博客网 时间:2024/04/30 02:54

题意:

一个神奇的国度他们字母类型有n个,并且每句话必须是m个字母组成的,但是国王很奇葩,他设定了一些单词,只要句子中出现这样的单词那么造句的人就好入狱。给出了p个不能出现的单词。问有多少种句子可以出现。

题解:

ac自动上的dp,第一次做参照了bin神的代码,很神奇啊,ac自动机上也可以dp 0 0!

好了我以自己理解来分析这题。

首先,我们要将所给的n个字符进行处理,因为这n个字符有可能不是以阿斯科马值相邻的,那么我们用map离散化。

接着,我们将限制的串插入自动机中,凡是出现end[i]==0的就是可行的串。

然后,建ac自动机时,要注意一点,如果适配指针对应的节点是限制串(fail[i]==1)那么对应的这个指向适配指正的对应节点也应该是限制串,这个要好好理解下。

最后我们只要这样设置状态dp[step][i]走了step步,并且以i节点为结尾的合法句子个数。只要枚举上一步的节点是哪个即可。注意要排出限制的:if(end[i]==1)continue;

最后一点,答案太大,要用大数存。我懒得写,可耻的盗用了别人的大数类。


#include<iostream>#include<math.h>#include<stdio.h>#include<algorithm>#include<string.h>#include<vector>#include<map>#include<set>using namespace std;#define B(x) (1<<(x))typedef long long ll;const int oo=0x3f3f3f3f;const ll OO=1LL<<61;const ll MOD=10007;const int maxn=1005;const int SIZE=110;char buff[maxn];map<char,int>mat;struct AC{    int next[SIZE][256],fail[SIZE],end[SIZE],Q[SIZE*256];    int root,cnt;    void Init()    {        cnt=0;        root=newNode();    }    int newNode()    {        for(int i=0;i<256;i++)            next[cnt][i]=-1;        end[cnt++]=0;        return cnt-1;    }    void Insert(char buff[])    {        int now=root;        int len=strlen(buff);        for(int i=0,k;i<len;i++)        {            k=mat[buff[i]];            if(next[now][k]==-1)                next[now][k]=newNode();            now=next[now][k];        }        end[now]=1;///这个单词是否存在    }    void build()    {        fail[root]=root;        int front,rear;        front=rear=0;        int now=root;        for(int i=0;i<256;i++)        {            if(next[now][i]==-1)                next[now][i]=root;            else            {                fail[next[now][i]]=root;                Q[rear++]=next[now][i];            }        }        while(front<rear)        {            now=Q[front++];            if(end[fail[now]]) end[now]=1;///这句话非常重要,没加wa一发            for(int i=0;i<256;i++)            {                if(next[now][i]==-1)                    next[now][i]=next[fail[now]][i];                else                {                    fail[next[now][i]]=next[fail[now]][i];                    Q[rear++]=next[now][i];                }            }        }    }/*    void Search(char buff[])    {        int now=root;        int len=strlen(buff);        for(int i=0;i<len;i++)        {            now=next[now][buff[i]];            int temp=now;            while(temp!=root)            {                if(end[temp])                    StrId.insert(end[temp]);                ans[end[temp]]++;                temp=fail[temp];            }        }    }*/    void Debug()    {        for(int i=0;i<cnt;i++)        {            printf("id=%3d fail=%3d end=%3d child=[",i,fail[i],end[i]);            for(int j=0;j<26;j++)                printf(" %3d",next[i][j]);            printf(" ]\n");        }    }};AC ac;///大数struct BigInt{    const static int mod = 10000;    const static int DLEN = 4;    int a[600],len;    BigInt()    {        memset(a,0,sizeof(a));        len = 1;    }    BigInt(int v)    {        memset(a,0,sizeof(a));        len = 0;        do        {            a[len++] = v%mod;            v /= mod;        }while(v);    }    BigInt(const char s[])    {        memset(a,0,sizeof(a));        int L = strlen(s);        len = L/DLEN;        if(L%DLEN)len++;        int index = 0;        for(int i = L-1;i >= 0;i -= DLEN)        {            int t = 0;            int k = i - DLEN + 1;            if(k < 0)k = 0;            for(int j = k;j <= i;j++)                t = t*10 + s[j] - '0';            a[index++] = t;        }    }    BigInt operator +(const BigInt &b)const    {        BigInt res;        res.len = max(len,b.len);        for(int i = 0;i <= res.len;i++)            res.a[i] = 0;        for(int i = 0;i < res.len;i++)        {            res.a[i] += ((i < len)?a[i]:0)+((i < b.len)?b.a[i]:0);            res.a[i+1] += res.a[i]/mod;            res.a[i] %= mod;        }        if(res.a[res.len] > 0)res.len++;        return res;    }    BigInt operator *(const BigInt &b)const    {        BigInt res;        for(int i = 0; i < len;i++)        {            int up = 0;            for(int j = 0;j < b.len;j++)            {                int temp = a[i]*b.a[j] + res.a[i+j] + up;                res.a[i+j] = temp%mod;                up = temp/mod;            }            if(up != 0)                res.a[i + b.len] = up;        }        res.len = len + b.len;        while(res.a[res.len - 1] == 0 &&res.len > 1)res.len--;        return res;    }    void output()    {        printf("%d",a[len-1]);        for(int i = len-2;i >=0 ;i--)            printf("%04d",a[i]);        printf("\n");    }};BigInt dp[2][SIZE];int main(){    int n,m,p;    while(scanf("%d %d %d",&n,&m,&p)!=EOF)    {        scanf("%s",buff);        mat.clear();        for(int i=0;buff[i];i++)            mat[buff[i]]=i;        ac.Init();        for(int i=1;i<=p;i++)        {            scanf("%s",buff);            ac.Insert(buff);        }        ac.build();        int now=0,pre=1;        dp[now][0]=1;        for(int i=1;i<ac.cnt;i++)            dp[now][i]=0;        for(int t=1;t<=m;t++)        {            now^=1;            pre^=1;            for(int i=0;i<ac.cnt;i++)                dp[now][i]=0;            for(int i=0;i<ac.cnt;i++)            {                if(ac.end[i])continue;///存在这样的路径跳过.                for(int j=0;j<n;j++)                {                    int k=ac.next[i][j];                    if(ac.end[k])continue;                    dp[now][k]=dp[now][k]+dp[pre][i];                }            }        }        BigInt ans=0;        for(int i=0;i<ac.cnt;i++)            ans=ans+dp[now][i];        ans.output();    }    return 0;}/**5 5 5abcdebeeedcbadeebbaedans=1024*/


0 0
原创粉丝点击