• [HNOI2008]GT考试


    题目描述

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

    输入输出格式

    输入格式:

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

    输出格式:

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

    输入输出样例

    输入样例#1:
    4 3 100
    111
    输出样例#1:
    81
    设f[i][j]表示:准考证号前i位中 后j位与不吉利数的前j位相同时的方案数 
    那么答案ans=f[n][0]+f[n][1]+…+f[n][m-1]
    为避免重复,f[i][j]表示的每种方案都不含长度大于j且与不吉利数的前缀相同的后缀 
    否则就会出现:
    从1到m标号,不吉利数为123124时,f[i][2]计数的方案包含f[i][5]计数的方案的情况 
    转移:f[i][j]=∑f[i-1][k]*a[k][j]

    a[k][j]为字符串中前缀1~k变成前缀1~j的方案数
    a数组用kmp预处理,在求出next后,对于每一个前缀1~i,在后面加入'0'~'9',进行匹配
    对于匹配的结果j,则a[i][j]++,匹配失败则f[i][0]++

    算法变成了O(n)还不够

    我们发现转移方程可以写成矩阵

    这样就可以用矩阵快速幂

    复杂度O(logn*m^3)

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 int Mod;
     7 int n,m,nxt[51];
     8 int ans;
     9 char s[51];
    10 struct Matrix
    11 {
    12     int num[51][51];
    13     Matrix init()
    14     {
    15         memset(num,0,sizeof(num));
    16     }
    17     Matrix operator*(const Matrix &x)
    18     {
    19         Matrix c;
    20         c.init();
    21         int i,j,k;
    22         for (i=0;i<m;i++)
    23         {
    24             for (j=0;j<m;j++)
    25             {
    26                 for (k=0;k<m;k++)
    27                 {
    28                     c.num[i][j]+=(num[i][k]*x.num[k][j])%Mod;
    29                     c.num[i][j]%=Mod;
    30                 }
    31             }
    32         }
    33         return c;
    34     }
    35 }a[51][51],S,T;
    36 void KMP()
    37 {int i,j,k;
    38     j=0;
    39     nxt[1]=0;
    40     for (i=2;i<=m;i++)
    41      {
    42         while (j&&s[j+1]!=s[i]) j=nxt[j];
    43         if (s[j+1]==s[i]) j++;
    44         nxt[i]=j;
    45      }
    46      j=0;
    47      for (i=0;i<m;i++)
    48      {
    49         for (k=0;k<=9;k++)
    50         {
    51             j=i;
    52              while (j&&s[j+1]!=(char)(k+'0')) j=nxt[j];
    53              if (s[j+1]==k+'0') T.num[i][j+1]++;
    54                else T.num[i][0]++; 
    55         }
    56      }
    57 }
    58 void qpow()
    59 {int i,j;
    60     for (i=0;i<m;i++)
    61      S.num[i][i]=1;
    62       while (n)
    63       {
    64             if (n&1)
    65             {
    66                 S=S*T;
    67             }
    68         T=T*T;
    69         n>>=1;
    70       }
    71 }
    72 int main()
    73 {int k,i,j;
    74 char ch;
    75     cin>>n>>m>>k;
    76     Mod=k;
    77     scanf("%s",s+1);
    78       KMP();
    79        qpow();
    80     for (i=0;i<m;i++)
    81      ans=(ans+S.num[0][i])%Mod;
    82     cout<<ans;
    83 }
  • 相关阅读:
    java基础英语---第十九天
    java基础英语---第十六天
    java基础英语---第十七天
    java基础英语---第十四天
    java基础英语---第十五天
    java基础英语---第十三天
    设计模式
    设计模式
    设计模式
    设计模式
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7374060.html
Copyright © 2020-2023  润新知