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

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 3531  Solved: 2154

    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

     

    Source

    KMP+DP+矩阵乘法优化

    f[i][j]表示当前处理到第i位,匹配到不吉利数字的第j位的方案数。

    然后枚举下一位数字填几,判断会转移到不吉利数字的第j位,累计方案数。

    理论正确,可以华丽地TLE

    考虑矩阵优化,把以上转移关系存到矩阵里,利用矩阵快速幂算出最后的方案数。累加所有匹配长度不到m的答案即可。

    KMP有什么用?用来预处理出nxt数组,快速判断失配时会转移到第几位。

    ——但是m长度才20,要KMP有什么用?

    ——这是一种思想,如果m更长,几百甚至几千,那当然要用KMP啦

    ——那就没法矩阵乘法了

    ——那……权当复习吧

     1 /*by SilverN*/
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<cstring>
     5 #include<cstdio>
     6 #include<cmath>
     7 #include<vector>
     8 #define LL long long
     9 using namespace std;
    10 const int mxn=100010;
    11 int read(){
    12     int x=0,f=1;char ch=getchar();
    13     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    14     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    15     return x*f;
    16 }
    17 int n,m,P;
    18 struct Mat{
    19     int a[30][30];
    20     Mat(){memset(a,0,sizeof a);}
    21     Mat operator * (const Mat y){
    22         Mat res;
    23         for(int i=0;i<m;i++){
    24             for(int j=0;j<m;j++){
    25                 for(int k=0;k<m;k++){
    26                     (res.a[i][j]+=a[i][k]*y.a[k][j])%=P;
    27                 }
    28             }
    29         }
    30         return res;
    31     }
    32 }bas,mp;
    33 int nxt[30];
    34 void getnext(char *s){
    35     nxt[0]=-1;int len=strlen(s);
    36     for(int i=1,j=-1;i<len;i++){
    37         while(j>=0 && s[i]!=s[j+1])j=nxt[j];
    38         if(s[i]==s[j+1])j++;
    39         nxt[i]=j;
    40     }
    41     for(int i=len;i;i--)nxt[i]=nxt[i-1]+1;
    42     nxt[0]=0;
    43 //    for(int i=0;i<=len;i++)printf("%d ",nxt[i]);
    44 //    printf("
    ");
    45     return;
    46 }
    47 char s[30];
    48 int main(){
    49     int i,j;
    50     n=read();m=read();P=read();
    51     scanf("%s",s+1);
    52     getnext(s+1);
    53     int len=strlen(s+1);
    54     for(i=0;i<len;i++){//匹配到的位置
    55         for(j=0;j<=9;j++){//下一位 
    56             int tmp=i;
    57             while(tmp && s[tmp+1]!=j+'0')tmp=nxt[tmp];
    58             if(s[tmp+1]==j+'0')tmp++;
    59             if(tmp!=len) (mp.a[tmp][i]+=1)%=P;
    60         }
    61     }
    62     for(i=0;i<=len;i++){
    63         bas.a[i][i]=1;
    64     }
    65     while(n){
    66         if(n&1)bas=bas*mp;
    67         mp=mp*mp;
    68         n>>=1;
    69     }
    70     int ans=0;
    71     for(i=len-1;i>=0;i--){
    72         ans=(ans+bas.a[i][0])%P;
    73     }
    74     printf("%d
    ",ans);
    75     return 0;
    76 }
  • 相关阅读:
    win8设置无线网络共享
    设计模式学习每天一个——Decorator模式
    【转】命令模式(command pattern)
    设计模式总览
    设计模式学习每天一个——Command模式
    设计模式学习每天一个——Observer模式
    【转】UML解惑:图说UML中的六大关系
    设计模式学习每天一个——Strategy模式
    深入学习
    设计模式学习每天一个——Singleton模式
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6511812.html
Copyright © 2011-2022 走看看