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

    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

    正解:$kmp$+矩阵快速幂加速。

    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]求法是个线性齐次递推式,可以构造成矩阵,然后加一下速。

    感觉自己还不是很理解。。慢慢推敲吧。。

     1 //It is made by wfj_2048~
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <cstring>
     5 #include <cstdlib>
     6 #include <cstdio>
     7 #include <vector>
     8 #include <cmath>
     9 #include <queue>
    10 #include <stack>
    11 #include <map>
    12 #include <set>
    13 #define inf (1<<30)
    14 #define il inline
    15 #define RG register
    16 #define ll long long
    17 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    18 
    19 using namespace std;
    20 
    21 struct data{ int a[30][30]; }a,b;
    22 
    23 int nxt[30],n,m,k,ans;
    24 char s[30];
    25 
    26 il int gi(){
    27     RG int x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    28     if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x;
    29 }
    30 
    31 il data mul(RG data a,RG data b){
    32     RG data c; memset(c.a,0,sizeof(c.a));
    33     for (RG int i=0;i<m;++i)
    34     for (RG int j=0;j<m;++j)
    35         for (RG int p=0;p<m;++p){
    36         c.a[i][j]+=a.a[i][p]*b.a[p][j]%k;
    37         if (c.a[i][j]>=k) c.a[i][j]-=k;
    38         }
    39     return c;
    40 }
    41 
    42 il void work(){
    43     n=gi(),m=gi(),k=gi(); scanf("%s",s+1);
    44     for (RG int i=2;i<=m;++i){
    45     RG int j=nxt[i-1];
    46     while (j && s[j+1]!=s[i]) j=nxt[j];
    47     if (s[j+1]==s[i]) nxt[i]=j+1;
    48     }
    49     for (RG int i=0;i<m;++i)
    50     for (RG int j=0;j<=9;++j){
    51         RG int t=i; while (t && s[t+1]!=j+'0') t=nxt[t]; if (s[t+1]==j+'0') t++;
    52         if (t!=m){ b.a[i][t]++; if (b.a[i][t]>=k) b.a[i][t]-=k; }
    53     }
    54     for (RG int i=0;i<m;++i) a.a[i][i]=1;
    55     while (n){ if (n&1) a=mul(a,b); b=mul(b,b); n>>=1; }
    56     for (RG int i=0;i<m;++i){ ans+=a.a[0][i]; if (ans>=k) ans-=k; }
    57     printf("%d
    ",ans); return;
    58 }
    59 
    60 int main(){
    61     File("gt");
    62     work();
    63     return 0;
    64 }
  • 相关阅读:
    UITableView多选全选
    iOS16进制设置颜色
    svg矢量图
    canvas 时钟案例
    canvas 方块旋转案例
    canvas万花筒案例
    swiper(轮播)组件
    canvas介绍(画布)
    scroll-view组件
    view组件
  • 原文地址:https://www.cnblogs.com/wfj2048/p/6576550.html
Copyright © 2011-2022 走看看