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

    1009: [HNOI2008]GT考试

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 2154  Solved: 1327
    [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位的数。 100%数据N<=10^9,M<=20,K<=1000 40%数据N<=1000 10%数据N<=6

    Output

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

    Sample Input

    4 3 100
    111

    Sample Output

    81

    HINT

     

    Source

    题解:做到这道题我很伤心。。。是ac(kmp)+dp

    翻了这么多题解还是cjk讲的最好。。。请允许我转一下。。。

    字符串上的动态规划:

    按顺序处理准考证号每一位,
    设f[i][j]表示:准考证号前i位中 后j位与不吉利数的前j位相同时,前i位的方案数 
    那么答案ans=f[n][0]+f[n][1]+…+f[n][m-1]

    f[i][j]的准确含义:
    1.f[i][j]表示的每种方案不仅与其后j位有关,还应保证不含不吉利数 
    2.为避免重复,f[i][j]表示的每种方案都不含长度大于j且与不吉利数的前缀相同 的后缀 
     否则就会出现:从1到m标号,不吉利数为123124时,f[i][2]计数的方案包含f[i][5]计数的方案 的情况 

    状态转移:
    f[i][j]只能由f[i-1][k]得到,相当于填完第i-1位后,将其后缀k(长为k的后缀)后面新添一位num,之后这个i位数的 与不吉利数前缀相同的最长后缀是:后缀j
    i>=1时:f[i][j]=f[i-1][0]*a[0][j]+f[i-1][1]*a[1][j]+…+f[i-1][m-1]*a[m-1][j]
            比如:还是假设不吉利数为123124,那么 f[i][3]=f[i-1][2]+f[i-1][5],因为 f[i-1][2]末尾的*****12不能是**12312,所以需要f[i-1][5]补充 
            但若不吉利数为123123,那么 f[i][3]=f[i-1][2],因为 f[i][3]末尾的*****123不能是**123123
    i==0时:f[0][0]=1,f[0][其他]=0
    其中,a[k][j]就表示上面提到的num能取几个值,可以用kmp算法预处理出来,它是一个矩阵 

    这样就可以不重不漏地计数了 

    再来个矩阵加速:f[i][j]求法是个线性齐次递推式,可以构造成矩阵,然后加一下速。

    这道题要留坑的。。。因为还不是很懂QAQ

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<queue>
     6 #include<cstring>
     7 #define PAU putchar(' ')
     8 #define ENT putchar('
    ')
     9 using namespace std;
    10 const int maxn=30;
    11 int n,mod,len,nxt[maxn];char str[maxn];
    12 struct matrix{int f[maxn][maxn];matrix(){memset(f,0,sizeof(f));}}m,ans;
    13 matrix operator*(const matrix&a,const matrix&b){
    14     matrix c;
    15     for(int i=0;i<len;i++)
    16         for(int j=0;j<len;j++)
    17             for(int k=0;k<len;k++)
    18                 c.f[i][j]=(c.f[i][j]+a.f[i][k]*b.f[k][j])%mod;
    19     return c;
    20 }
    21 void kmp(){
    22     int j=0;nxt[1]=0;
    23     for(int i=2;i<=len;i++){
    24         while(j&&str[j+1]!=str[i]) j=nxt[j];
    25         if(str[j+1]==str[i])j++;nxt[i]=j;
    26     }return;
    27 }
    28 void dp(){
    29     for(int i=0;i<len;i++)
    30         for(int j=0;j<10;j++){
    31             int k;
    32             for(k=i;k;k=nxt[k]) if(str[k+1]-'0'==j) break;
    33             if(str[k+1]-'0'==j) k++;
    34             m.f[i][k]=(m.f[i][k]+1)%mod;
    35         }
    36     return;
    37 }
    38 void pow(){
    39     for(int i=0;i<len;i++) ans.f[i][i]=1;
    40     for(;n;n>>=1,m=m*m)if(n&1) ans=ans*m;return;
    41 }
    42 inline int read(){
    43     int x=0,sig=1;char ch=getchar();
    44     while(!isdigit(ch)){if(ch=='-') sig=-1;ch=getchar();}
    45     while(isdigit(ch)) x=10*x+ch-'0',ch=getchar();
    46     return x*sig;
    47 }
    48 inline void write(int x){
    49     if(x==0){putchar('0');return;}if(x<0) putchar('-'),x=-x;
    50     int len=0,buf[15];while(x) buf[len++]=x%10,x/=10;
    51     for(int i=len-1;i>=0;i--) putchar(buf[i]+'0');return;
    52 }
    53 int main(){
    54     n=read();len=read();mod=read();scanf("%s",str+1);kmp();dp();pow();
    55     int res=0;for(int i=0;i<len;i++) res=(res+ans.f[0][i])%mod;
    56     write(res);
    57     return 0;
    58 }
  • 相关阅读:
    Firefox浏览器怎么安装adobe flash player插件
    uploadify在火狐下上传不了的解决方案,java版(Spring+SpringMVC+MyBatis)详细解决方案...
    thinkphp模版调用函数方法
    Thinkphp模板中函数的使用
    60.0.1(64位)windows版 uploadify使用有问题
    一起谈.NET技术,异步调用与多线程的区别 狼人:
    一起谈.NET技术,Silverlight中使用递归构造关系图 狼人:
    一起谈.NET技术,ASP.NET Routing对请求的处理方式 狼人:
    一起谈.NET技术,闲话“多线程” 狼人:
    一起谈.NET技术,利用.NET Framework4.0的源代码调试你的应用程序 狼人:
  • 原文地址:https://www.cnblogs.com/chxer/p/4642446.html
Copyright © 2011-2022 走看看