bzoj 1009 GT考试(dp+KMP)

版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载,欢迎添加友链。 https://blog.csdn.net/zzk_233/article/details/82852615

我的算法和大部分的题解算法有些不同。。。。算法来源参照http://acm.hdu.edu.cn/showproblem.php?pid=3689

那么这道题的思想可以转为求,当准考证号的长度为i时不吉利数字匹配的长度为j,那么设f[i][j]表示当前状态的方案数,则有转移

f[i][kmp(j-1,k)]+=f[i-1][j-1];

j为长度,因为kmp是从0开始的,所以他的位置为j-1,即求出下一个字符为k时的匹配位置。那么最后求出 \sum_{i=1}^{m-1}f[n][i] 即可

暴力代码

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
char ss[25];
int nxt[25],l;
int f[1005][25];
void gett()
{
    int t1=0,t2=-1;
    nxt[0]=-1;
    while(t1<l)
    {
        if(t2==-1||ss[t1]==ss[t2])
        {
            t1++,t2++;
            nxt[t1]=t2;
        }else 
        {
            t2=nxt[t2];
        }
    }
}
int kmp(int q,int w)
{
    while((q!=-1)&&((ss[q]-'0')!=w))
    {
        q=nxt[q];
    }
    return q+1;
}
int main()
{
    int n,m,K;
    scanf("%d%d%d",&n,&m,&K);
    scanf("%s",ss);
    l=strlen(ss);
    gett();
    f[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=l;j++)
        {
            for(int k=0;k<=9;k++)
            {
                f[i][kmp(j-1,k)]+=f[i-1][j-1]%K;
                f[i][kmp(j-1,k)]%=K;
            }
        }
    }
    int ans=0;
    for(int j=0;j<l;j++)
    {
        ans+=f[n][j];
        ans%=K;
    }
    printf("%d",ans);
    return 0;
}

而我们发现每次转移的kmp都是固定的,所以可以矩阵乘法求出。

代码

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
char ss[25];
int nxt[25],l;
int n,m,K;
void gett()
{
    int t1=0,t2=-1;
    nxt[0]=-1;
    while(t1<l)
    {
        if(t2==-1||ss[t1]==ss[t2])
        {
            t1++,t2++;
            nxt[t1]=t2;
        }else 
        {
            t2=nxt[t2];
        }
    }
}
int kmp(int q,int w)
{
    while((q!=-1)&&((ss[q]-'0')!=w))
    {
        q=nxt[q];
    }
    return q+1;
}
struct node 
{
    int f[30][30];
}dp,zy;
node operator *(node a,node b)
{
    node ans1;
    memset(ans1.f,0,sizeof(ans1.f));
    for(int i=0;i<=25;i++)
    {
        for(int j=0;j<=25;j++)
        {
            for(int k=0;k<=25;k++)
            {
                ans1.f[i][j]+=a.f[i][k]*b.f[k][j]%K;
                ans1.f[i][j]%=K;
            }
        }
    }
    return ans1;
}
void ksm(node a,int b)
{
    while(b)
    {
        if(b%2==1)
        {
            dp=a*dp;
        }
        b=b/2;
        a=a*a;
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&K);
    scanf("%s",ss);
    l=strlen(ss);
    gett();
    for(int j=1;j<=l;j++)
    {
        for(int k=0;k<=9;k++)
        {
            zy.f[kmp(j-1,k)][j-1]++;
        }
    }
    dp.f[0][0]=1;
    ksm(zy,n);
    int ans=0;
    for(int i=0;i<l;i++)
    {
        ans+=dp.f[i][0];
        ans%=K;
    }
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zzk_233/article/details/82852615