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

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 4779  Solved: 2977
    [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
     
    最近被填志愿弄得很烦,家长各种建议→_→,学校那边三天一小会,五天一大会。。。嘛,成都再见(。・_・)/~~~
     
    本题是一道DP+矩阵乘法,推理过程如下:
    首先我们可以设一个数组f[i][j],i表示准考证号匹配到了第i位,j表示不吉利数字匹配到了第j位,f[i][j]表示有多少种符合条件的号码
    因此可以看出f[i+1][k]取决于f[i][j]后下一位填的数字
    以范例为例,假设:准考证匹配到了第2位,不吉利号码匹配到了第1位,那么f[3][0]=f[2][0]*9+f[2][1]*9+f[2][2]*0,f[3][1]=f[2][0]*1+f[2][1]*0+f[2][2]*0
    因为如果下一位不填1的情况有9种,而不填1都会导致不吉利号码匹配到0位因此有九种情况
    因此可以得出公式:
    [f[i][j]=sum_{k=0}^{m-1} f[i-1][k]*g[k][j]]
    g[i][j]代表从第j位匹配到第i位能填几种数字,因此我们只要求出g[i][j]就完成了最难的部分,这部分可以通过kmp+枚举来求
    但是直接for循环10^9的数量级无疑会TLE,因此这里需要使用矩阵加速
     
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 
     6 char ch[30];
     7 int p[30],g[30][30],f[30][30];
     8 int n,m,mod,ans;
     9 
    10 void initnext(char *t,int *p)
    11 {
    12     int j=0;
    13     for(int i=1;i<m;i++)
    14     {
    15         while(j&&t[i]!=t[j]) j=p[j];
    16         if(t[i]==t[j]) j++;
    17         p[i+1]=j;
    18     }
    19 }
    20 
    21 void mult(int a[30][30],int b[30][30],int ans[30][30])
    22 {
    23     int tmp[30][30];
    24     memset(tmp,0,sizeof(tmp));
    25     for(int i=0;i<m;i++)
    26         for(int j=0;j<m;j++)
    27             for(int k=0;k<m;k++)
    28                 tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%mod;
    29     for(int i=0;i<m;i++)
    30         for(int j=0;j<m;j++)
    31             ans[i][j]=tmp[i][j];
    32 }
    33 
    34 int main()
    35 {
    36     scanf("%d %d %d",&n,&m,&mod);
    37     scanf("%s",ch);
    38     initnext(ch,p);//求出前缀数组
    39     for(int i=0;i<m;i++)//转移计算
    40         for(int j=0;j<=9;j++)
    41         {
    42             int t=i;
    43             while(t>0&&ch[t]-'0'!=j)
    44                 t=p[t];
    45             if(ch[t]-'0'==j) t++;
    46             if(t!=m) g[t][i]=(g[t][i]+1)%mod;
    47         }
    48     for(int i=0;i<m;i++)
    49         f[i][i]=1;
    50 
    51     while(n)
    52     {
    53         if(n&1) mult(f,g,f);
    54         mult(g,g,g);
    55         n>>=1;
    56     }
    57     for(int i=0;i<m;i++)
    58         ans=(ans+f[i][0])%mod;
    59     printf("%d
    ",ans);
    60     return 0;
    61 }
  • 相关阅读:
    python 合并 Excel 单元格
    python 设置 Excel 表格的行高和列宽
    Python 用 openpyxl 模块统计 Excel 表格中的数据,以字典形式写入 py 文件
    python 打印字母阶梯和金字塔
    python 用 openpyxl 读取 Excel 表格中指定的行或列
    Python 的 filter() 函数
    Python 的 map() 函数
    python 之 range() 函数
    python 的 reduce() 函数
    python 之 lambda 函数
  • 原文地址:https://www.cnblogs.com/InWILL/p/9236222.html
Copyright © 2011-2022 走看看