BZOJ1009 单模板自动机 矩阵快速幂优化DP

来源:互联网 发布:纳粹十字勋章淘宝 编辑:程序博客网 时间:2024/06/05 13:30

第一次在BZOJ自己做出不是那么水的题,但是看这过题人数。。。嘛还是写一下题解吧

题目大意:求只由0到9组成的不包含m(m<=20)位模式串的n(n<=1e9)位字符串的个数

涉及到字符串匹配的话 很自然应该往KMP和自动机的方向想。
然后可以很容易发现建自动机可以得到一个DP做法:
定义dp[i][j]为前i位到达状态j的方案数
那么对每个next[j][k]!=m,
都有dp[i+1][next[j][k]]+=dp[i][j] ,
那么答案就是dp[n][i]
然后n很大 那么就矩阵快速幂吧
至此问题完美解决!

代码:

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<algorithm>#include<string>#include<iomanip>#include<vector>#include<set>#include<map>#include<queue>using namespace std;typedef long long LL;typedef unsigned long long ULL;#define rep(i,k,n) for(int i=(k);i<=(n);i++)#define rep0(i,n) for(int i=0;i<(n);i++)#define red(i,k,n) for(int i=(k);i>=(n);i--)#define sqr(x) ((x)*(x))#define clr(x,y) memset((x),(y),sizeof(x))#define pb push_backconst int maxn=100;const int maxs=10;int n,m,mod;int nxt[maxn][maxs],fail[maxn];int root,tot;int newnode(){    for(int i=0;i<maxs;i++)nxt[tot][i]=-1;    return tot++;}void init(){    tot=0;    root=newnode();}void insert(char str[]){    int len=strlen(str);    int now=root;    for(int i=0;i<len;i++)    {        char s=str[i]-'0';        if(nxt[now][s]==-1)            nxt[now][s]=newnode();        now=nxt[now][s];    }}void build(){    queue<int> q;    fail[root]=root;    for(int i=0;i<maxs;i++)    {        if(nxt[root][i]==-1)            nxt[root][i]=root;        else        {            fail[nxt[root][i]]=root;            q.push(nxt[root][i]);        }    }    while(!q.empty())    {        int now=q.front();        q.pop();        for(int i=0;i<maxs;i++)        {            if(nxt[now][i]==-1)                nxt[now][i]=nxt[fail[now]][i];            else            {                fail[nxt[now][i]]=nxt[fail[now]][i];                q.push(nxt[now][i]);            }        }    }}struct MAT{    int a[25][25];    int n;    void init(int x,int m)    {        clr(a,0);        n=m;        if(x)rep0(i,n)a[i][i]=1;    }    MAT operator * (const MAT &x) const    {        MAT ret;ret.init(0,n);        rep0(i,n)rep0(j,n)rep0(k,n)(ret.a[i][j]+=a[i][k]*x.a[k][j]%mod)%=mod;        return ret;    }    void add(int x,int y)    {        a[x][y]++;    }};MAT quipow(MAT x,LL k){    MAT ret;ret.init(1,x.n);    while(k)    {        if(k&1)ret=ret*x;        x=x*x;        k>>=1;    }    return ret;}char str[30];int main(){    scanf("%d%d%d",&n,&m,&mod);    scanf("%s",str);    init();    insert(str);    build();    MAT A;A.init(0,m);    rep0(i,m)    {        rep0(j,10)        {            if(nxt[i][j]!=m)            {                A.add(nxt[i][j],i);            }        }    }    MAT B=quipow(A,n);    int ans=0;    rep0(i,m)ans+=B.a[i][0];    printf("%d\n",ans%mod);    return 0;}
0 0
原创粉丝点击