zoukankan      html  css  js  c++  java
  • BZOJ_1009_[HNOI2008]GT考试_KMP+矩阵乘法

    BZOJ_1009_[HNOI2008]GT考试_KMP+矩阵乘法

    Description

      阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。
    他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为0

    Input

      第一行输入N,M,K.接下来一行输入M位的数。 N<=10^9,M<=20,K<=1000

    Output

      阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.

    Sample Input

    4 3 100
    111

    Sample Output

    81

    设F[i][j]表示长度为i的串,已经和模式串匹配到第j位有多少种方案。
    然后枚举第i位是啥,转移就是F[i-1][k]->F[i][j],k为加入第i位前在模式串中匹配到哪一位。
    其中(k,j)可以用KMP求出(其实暴力找下一位匹配的位置就可以)
    同时要保证不能匹配到最后一位,即j不能为m。
    然后用矩阵乘法加速这个转移过程。
     
    代码:
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    int mod,n,m,nxt[25];
    char s[25];
    struct Mat {
        int v[21][21];
        Mat(){memset(v,0,sizeof(v));}
        Mat operator*(const Mat &x)const {
            Mat re;int i,j,k;
            for(i=0;i<=m;i++) {
                for(j=0;j<=m;j++) {
                    for(k=0;k<=m;k++) {
                        (re.v[i][j]+=v[i][k]*x.v[k][j]%mod)%=mod;
                    }
                }
            }
            return re;
        }
    };
    void print(Mat w) {
        int i,j;
        for(i=0;i<=m;i++) {
            for(j=0;j<=m;j++) {
                printf("%d ",w.v[i][j]);
            }puts("");
        }
    }
    Mat qp(Mat x,int y) {
        Mat I;
        int i;
        for(i=0;i<=m;i++) I.v[i][i]=1;
        while(y) {
            if(y&1) I=I*x;
            x=x*x;
            y>>=1;
        }
        return I;
    }
    void getnxt() {
        int i=0,j=-1;
        nxt[0]=-1;
        while(i<m) {
            if(j==-1||s[i]==s[j]) nxt[++i]=++j;
            else j=nxt[j];
        }
    }
    int main() {
        scanf("%d%d%d%s",&n,&m,&mod,s);
        int i,j,k;
        getnxt();
        Mat x,ans;
        for(i=0;i<m;i++) {
            for(j=0;j<=9;j++) {
                k=i;
                while(k!=-1&&s[k]-'0'!=j) k=nxt[k];
                x.v[i][k+1]++;
            }
        }
        ans.v[0][0]=1;
        ans=ans*qp(x,n);
        int sum=0;
        for(i=0;i<m;i++) sum=(sum+ans.v[0][i])%mod;
        printf("%d
    ",sum);
    }
    
  • 相关阅读:
    熟悉常用的HDFS操作
    爬虫爬取小说网站
    数据结构化与保存
    使用正则表达式,取得点击次数,函数抽离
    爬取校园新闻首页的新闻
    网络爬虫基础练习
    综合练习:词频统计
    最近在学习多元分析,有空放上来分享
    机器学习基石作业一15-20题(Python实现)
    2018十月份
  • 原文地址:https://www.cnblogs.com/suika/p/8996226.html
Copyright © 2011-2022 走看看