其他分享
首页 > 其他分享> > P3193 [HNOI2008]GT考试

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("\n");
    }*/
    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;
}

标签:Kano,GT,匹配,P3193,..,int,数字串,HNOI2008,20
来源: https://www.cnblogs.com/Fast-Bird/p/12047559.html