• 【BZOJ1009】GT考试(KMP算法,矩阵快速幂,动态规划)


    【BZOJ1009】GT考试(KMP算法,矩阵快速幂,动态规划)

    题面

    BZOJ

    题解

    看到这个题目
    化简一下题意
    长度为(n)的,由(0~9)组成的字符串中
    不含串(s)的串的数量有几个

    很显然,如果组成的字符串和(s)串做(KMP)的匹配的话
    是不能匹配到最后一位的

    所以,我们想到一个很显然的方程
    (f[i][j])表示当前做了第(i)位,在(s)串中匹配到了第(j)
    每次枚举下一位放的数字
    以及每一位的位置
    相当于做(KMP)的匹配
    然后进行转移

    所以,我们可以写出一个暴力

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    inline int read()
    {
    	int x=0,t=1;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=-1,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return x*t;
    }
    int f[2000][30];
    int nt[30],n,m,K;
    char s[30];
    void Get_Next(char *s)
    {
    	int l=strlen(s+1);
    	nt[1]=0;
    	for(int i=2;i<=l;++i)
    	{
    		int t=nt[i-1];
    		while(t&&s[i]!=s[t+1])t=nt[t];
    		if(s[i]==s[t+1])t+=1;
    		nt[i]=t;
    	}
    }
    int main()
    {
    	n=read();m=read();K=read();
    	scanf("%s",s+1);
    	Get_Next(s);
    	f[0][0]=1;
    	for(int i=0;i<n;++i)
    	{
    		for(int j='0';j<='9';++j)
    		{
    			for(int k=0;k<m;++k)
    			{
    				int t=k;
    				while(t&&s[t+1]!=j)t=nt[t];
    				if(j==s[t+1])t++;
    				(f[i+1][t]+=f[i][k])%=K;
    			}
    		}
    	}
    	int ans=0;
    	for(int i=0;i<m;++i)ans+=f[n][i];
    	printf("%d
    ",ans%K);
    	return 0;
    }
    
    

    (n)的范围有(10^9)
    不可能是(O(n))解了
    我们发现每次匹配的转移关系是一定的
    所以可以用矩阵快速幂来优化(dp)转移

    复杂度为(O(n+m^3logn))

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    inline int read()
    {
    	int x=0,t=1;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=-1,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return x*t;
    }
    int nt[30],n,m,K;
    char s[30];
    void Get_Next(char *s)
    {
    	int l=strlen(s+1);
    	nt[1]=0;
    	for(int i=2;i<=l;++i)
    	{
    		int t=nt[i-1];
    		while(t&&s[i]!=s[t+1])t=nt[t];
    		if(s[i]==s[t+1])t+=1;
    		nt[i]=t;
    	}
    }
    struct Dalao
    {
    	int s[30][30];
    	void init()
    		{
    			memset(s,0,sizeof(s));
    			for(int i=0;i<m;++i)s[i][i]=1;
    		}
    	void clear(){memset(s,0,sizeof(s));}
    }G;
    Dalao operator*(Dalao a,Dalao b)
    {
    	Dalao ret;ret.clear();
    	for(int i=0;i<m;++i)
    		for(int j=0;j<m;++j)
    			for(int k=0;k<m;++k)
    				(ret.s[i][j]+=a.s[i][k]*b.s[k][j]%K)%=K;
    	return ret;
    }
    Dalao fpow(Dalao a,int b)
    {
    	Dalao s;s.init();
    	while(b){if(b&1)s=s*a;a=a*a;b>>=1;}
    	return s;
    }
    int main()
    {
    	n=read();m=read();K=read();
    	scanf("%s",s+1);
    	Get_Next(s);
    	for(int j='0';j<='9';++j)
    	{
    		for(int k=0;k<m;++k)
    		{
    			int t=k;
    			while(t&&s[t+1]!=j)t=nt[t];
    			if(j==s[t+1])t++;
    			G.s[k][t]++;
    		}
    	}
    	G=fpow(G,n);
    	int ans=0;
    	for(int i=0;i<m;++i)ans=(ans+G.s[0][i])%K;
    	printf("%d
    ",ans%K);
    	return 0;
    }
    
    
  • 相关阅读:
    OCP-1Z0-053-200题-77题-654
    OCP-1Z0-053-200题-45题-623
    OCP-1Z0-053-200题-46题-624
    OCP-1Z0-053-200题-48题-626
    OCP-1Z0-053-200题-49题-627
    OCP-1Z0-053-V13.02-619题
    OCP-1Z0-053-200题-43题-678
    OCP-1Z0-053-200题-44题-622
    OCP-1Z0-053-V13.02-512题
    OCP-1Z0-053-200题-38题-617
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8310580.html
Copyright © 2020-2023  润新知