zoukankan      html  css  js  c++  java
  • bzoj1009 [HNOI2008] GT考试 矩阵乘法+dp+kmp

    1009: [HNOI2008]GT考试

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 4542  Solved: 2815
    [Submit][Status][Discuss]

    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

    HINT

     

    矩阵乘法的题题解写起来都十分麻烦。。

    而且很多东西只能意会。。

    f[i , j]表示前 i 个准考证号匹配到不吉利串第 j 个的方案

    然后你需要把一个答案矩阵f[i , j]转移到f[i+1 , j]

    举个例子,样例,比如当前匹配到了第2位,也就是说前 i 位的结尾是11

    对于第 i+1 个字符,如果是 1 的话,接着匹配到不吉利串第 3 位,不是 1 的话就匹配到第 0 位了

    也就是说前 i 位匹配到了不吉利串 j 位,加入 i+1 这个字符,有不同情况,有一些会转移到j+1,一些会转移到其他的,写成一些形如f[i+1 , k] += f[i , j]的式子……

    f[i+1 , 3] += f[i , 2]

    f[i+1 , 0] += f[i , 2]

    即枚举i+1可能出现的字符,然后看n个f[i , j]分别转移到哪去,就在转移矩阵的这个转移路径上+1

    按照这个思路用kmp写出转移矩阵,事实上暴力应该就行了

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring> 
     4 using namespace std;
     5 inline int read()
     6 {
     7     char ch=getchar();
     8     int f=1,x=0;
     9     while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
    10     while(ch>='0'&&ch<='9'){x=x*10+(ch-'0');ch=getchar();}
    11     return x*f;
    12 }
    13 int n,m,mod;
    14 int p[25];
    15 char ch[25];
    16 int a[25][25],b[25][25];
    17 void mul(int a[25][25],int b[25][25],int ans[25][25])
    18 {
    19     int tmp[25][25];
    20     for(int i=0;i<m;i++)
    21         for(int j=0;j<m;j++)
    22         {
    23             tmp[i][j]=0;
    24             for(int k=0;k<m;k++)
    25                 tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%mod;
    26         }
    27     for(int i=0;i<m;i++)
    28         for(int j=0;j<m;j++)
    29             ans[i][j]=tmp[i][j];
    30 }
    31 int main() 
    32 {
    33     n=read();m=read();mod=read();
    34     scanf("%s",ch+1);
    35     int j=0;
    36     for(int i=2;i<=m;i++)
    37     {
    38         while(j>0&&ch[j+1]!=ch[i])j=p[j];
    39         if(ch[j+1]==ch[i])j++;
    40         p[i]=j;
    41     }
    42     for(int i=0;i<m;i++)
    43        for(int j=0;j<=9;j++)
    44        {
    45                int t=i;
    46             while(t>0&&ch[t+1]-'0'!=j)
    47                 t=p[t];
    48             if(ch[t+1]-'0'==j)t++;
    49             if(t!=m)b[t][i]=(b[t][i]+1)%mod;
    50        }
    51     for(int i=0;i<m;i++)
    52         a[i][i]=1;
    53     while(n)
    54     {
    55         if(n&1)mul(a,b,a);
    56         mul(b,b,b);
    57         n>>=1;
    58     }
    59     int sum=0; 
    60     for(int i=0;i<m;i++)
    61         sum=(sum+a[i][0])%mod;
    62     printf("%d",sum);
    63     return 0;
    64 }

     

  • 相关阅读:
    getopt 命令行参数解析
    Linux下使用indent整理代码
    终端常用快捷键
    gedit 乱码解决
    linux sysrq
    linux下的文件审计功能(audit inotify)
    gdb基本命令
    linux shell 字符截断
    linux 设置时间 date命令
    Ubuntu 时间同步
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8530477.html
Copyright © 2011-2022 走看看