zoukankan      html  css  js  c++  java
  • P3193 [HNOI2008]GT考试

    题意

    给定数字串 A[1..m]
    构造一个数字串 X[1..n],使得串中不出现数字串 A
    求出方案数模 k 的结果 n≤10^9 ,m≤20,k≤1000

    分析

    设答案为f[][].
    f[i][j]表示当前X是在1-i时,匹配到A的第j个数字.
    如果i+1选择的数字=A[j+1],那么就直接转移.
    否则转移到f[i+1][next[j]+1].
    对于A的每一个位置,每一次转移的方案数都是一定的.
    所以可以直接跑一个矩阵,在乘上n次幂就可以了.
    矩阵a[i][j]表示从第j位开始构造,最后匹配到第i位的方案数.此处i是下一个应该匹配的.
    eg:如果i==m,那么就相当于我刚刚匹配的是第m-1位,匹配成功了,但是还没有匹配m,也是一个方案.

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=104;
    int n,m,p,nex[N];
    char s[N];
    struct Kano{
    	int a[20][20];
    	Kano(){
    		memset(a,0,sizeof a);
    	}
    	void get(){
    		for(int i=0;i<m;i++)
    			a[i][i]=1;
    	}
    	Kano operator*(const Kano &b)const{
    		Kano c;
    		for(int k=0;k<m;k++)
    			for(int i=0;i<m;i++)
    				for(int j=0;j<m;j++)
    					c.a[i][j]+=a[i][k]*b.a[k][j],c.a[i][j]%=p;
    		return c;
    	}
    }kano,f;
    void kmp(){
    	int j=0;
    	for(int i=1;i<m;i++){
    		while(j&&s[i]!=s[j]) j=nex[j];
    		if(s[i]==s[j]) j++;
    		nex[i+1]=j;
    	}
    }
    Kano ksm(int x){
    	if(x==1)
    		return kano;
    	Kano t=ksm(x>>1);
    	t=t*t;
    	if(x&1)
    		t=t*kano;
    	return t;
    }
    int main(){
    	std::ios::sync_with_stdio(false);
    	cin>>n>>m>>p>>s;
    	kmp();
    	for(int i=0;i<m;i++)
    		for(int ch='0';ch<='9';ch++){
    			int j=i;
    			while(j&&s[j]!=ch) j=nex[j];
    			if(s[j]==ch) j++;
    			if(j!=m)
    				kano.a[j][i]++;
    		}
    	/*Kano k=kano*kano;
    	for(int i=0;i<m;++i){
    		for(int j=0;j<m;++j)
    			printf("%d",k.a[i][j]);
    		printf("
    ");
    	}*/
    	f.a[0][0]=1;
    	f=ksm(n)*f;
    	int ans=0;
    	for(int i=0;i<m;i++)
    		ans=(ans+f.a[i][0])%p;
    	cout<<ans;
    }
    
  • 相关阅读:
    C#学习笔记
    Visual Studio 快捷键
    java 8 中lambda表达式学习
    Spfa算法
    dijkstra算法
    topSort
    并查集--学习详解
    trie树--详解
    POJ1988 并查集的使用
    Mybatis的一级缓存和二级缓存
  • 原文地址:https://www.cnblogs.com/Fast-Bird/p/12047559.html
Copyright © 2011-2022 走看看