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

    1009: [HNOI2008]GT考试

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 4474  Solved: 2763
    [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

    HINT

    Source

    【题解】

    不妨设dp[i][j]表示前i个字符,后缀有j个匹配上了,其余的没有匹配上

    他们说做多了AC自动机上DP就能想出这个状态。。

    可我还没写过AC自动机的题

    预处理a[i][j]表示长度为i的前缀加上一个字符到达长度为j的前缀的方案数

    转移为dp[i][j] = Σdp[i-1][k] * a[k][j]

    很明显的矩阵乘法

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cstdlib>
      5 #include <algorithm>
      6 #include <queue>
      7 #include <vector>
      8 #include <cmath> 
      9 #define min(a, b) ((a) < (b) ? (a) : (b))
     10 #define max(a, b) ((a) > (b) ? (a) : (b))
     11 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
     12 inline void swap(int &a, int &b)
     13 {
     14     long long tmp = a;a = b;b = tmp;
     15 }
     16 inline void read(int &x)
     17 {
     18     x = 0;char ch = getchar(), c = ch;
     19     while(ch < '0' || ch > '9') c = ch, ch = getchar();
     20     while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
     21     if(c == '-') x = -x;
     22 }
     23 
     24 const int INF = 0x3f3f3f3f;
     25 const int MAXM = 30;
     26 
     27 int a[MAXM][MAXM], p[MAXM][MAXM], nxt[MAXM], k, n, m;
     28 char s[MAXM];
     29 
     30 void kmp()
     31 {
     32     nxt[0] = -1;
     33     for(register int i = 1, j = -1;i < m;++ i)
     34     {
     35         while(j >= 0 && s[i] != s[j + 1]) j = nxt[j];
     36         if(s[i] == s[j + 1]) ++ j;
     37         nxt[i] = j;
     38     }
     39     for(register int i = 0;i < m;++ i)
     40         for(register int j = '0';j <= '9';++ j)
     41         {
     42             int tmp = i - 1;
     43             while(tmp >= 0 && s[tmp + 1] != j) 
     44                 tmp = nxt[tmp];
     45             if(s[tmp + 1] == j) ++ a[i][tmp + 2];
     46             else ++ a[i][0]; 
     47         }
     48 }
     49 
     50 int tmp[MAXM][MAXM], base[MAXM][MAXM];
     51 
     52 void pow(int b)
     53 {
     54     for(register int i = 0;i < m;++ i)
     55         for(register int j = 0;j < m;++ j)
     56             base[i][j] = a[i][j];
     57     for(;b;b >>= 1)
     58     {
     59         if(b & 1)
     60         {
     61             memset(tmp, 0, sizeof(tmp));
     62             for(register int i = 0;i < m;++ i)
     63                 for(register int j = 0;j < m;++ j)
     64                     for(register int q = 0;q < m;++ q)
     65                     {
     66                         tmp[i][j] += a[i][q] * base[q][j] % k;
     67                         if(tmp[i][j] >= k) tmp[i][j] -= k;
     68                     }
     69             for(register int i = 0;i < m;++ i)
     70                 for(register int j = 0;j < m;++ j)
     71                     a[i][j] = tmp[i][j];
     72         }
     73         memset(tmp, 0, sizeof(tmp));
     74         for(register int i = 0;i < m;++ i)
     75             for(register int j = 0;j < m;++ j)
     76                 for(register int q = 0;q < m;++ q)
     77                 {
     78                     tmp[i][j] += base[i][q] * base[q][j] % k;
     79                     if(tmp[i][j] >= k) tmp[i][j] -= k;
     80                 }
     81         for(register int i = 0;i < m;++ i)
     82                 for(register int j = 0;j < m;++ j)
     83                     base[i][j] = tmp[i][j];
     84     } 
     85 } 
     86 
     87 int main()
     88 {
     89     read(n), read(m), read(k);scanf("%s", s);
     90     kmp();
     91     pow(n - 1);
     92     int sum = 0;
     93     for(register int i = 0;i < m;++ i) 
     94     { 
     95         sum += a[0][i];
     96         if(sum >= k) sum -= k;
     97     } 
     98     printf("%d", sum);
     99     return 0;
    100 }
    BZOJ1009
  • 相关阅读:
    [Project Euler] 来做欧拉项目练习题吧: 题目002(转)
    [Project Euler] 欧拉项目练习题001(转)
    Linux wc 结合cat命令统计代码行数
    mysql:主键和索引的区别
    一些常用的SQL语句
    mysql 性能优化方案
    修改mysql用户密码
    Ruby on Rails,创建开发用的MYSQL数据库
    mysql数据库中分区的概念
    Rails 数据库操作
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/8320807.html
Copyright © 2011-2022 走看看