zoukankan      html  css  js  c++  java
  • GT考试

    题目:阿申准备报名参加GT考试,准考证号为n位数(X1X2...Xn,)他不希望准考证号上出现不吉利的数字。他的不吉利数字(A1A2...Am)有m位,不出现是指(X1X2...Xn)中没有恰好一段等于(A1A2...Am)(A1)(X1)可以为0。

    (输入格式)
    第一行输入(n,m,K)
    接下来一行输入m位的不吉利数字

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

    分析
    我们定义f[i, j]为所有长度为i,且不包含不吉利字符串,且末尾部分与不吉利字符串的前缀匹配的最大长度是j的所有字符串的方案集合。

    我们可以得到(f[i, j] = sumlimits_{k = 0}^{m - 1}f[i - 1][k] * a[k][j]),a[k][j]表示已匹配k位,再匹配一个字符,就是j位的方案数,那么我们发现每一层的((f[i, 0], f[i, 1], f[i, 2], ...f[i, n - 1], f[i, n]))都会乘以固定的a[][],我们可以预先处理出这个a矩阵,使用KMP算法

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 25;
    
    int n, m, mod;
    
    char str[N];
    int ne[N];
    
    int a[N][N];
    
    void mul(int c[][N], int a[][N], int b[][N])
    {
        static int t[N][N];
        memset(t, 0, sizeof t);
        
        for(int i = 0; i < m; ++i)
            for(int j = 0; j < m; ++j)
                for(int k = 0; k < m; ++k)
                    t[i][j] = (t[i][j] + a[i][k] * b[k][j]) % mod;
        
        memcpy(c, t, sizeof t);
    }
    
    int qmi(int k)
    {
        int f[N][N] = {1};
        
        while(k)
        {
            if(k & 1) mul(f, f, a);
            mul(a, a, a);
            k >>= 1;
        }
        
        int res = 0;
        for(int i = 0; i < m; ++i) res = (res + f[0][i]) % mod;
        return res;
    }
    
    int main()
    {
        //准考证号和不吉利数字位数
        cin >> n >> m >> mod;
        cin >> str + 1;
        
        //求不吉利字符串的ne数组
        for(int i = 2, j = 0; i <= m; ++i)
        {
            while(j && str[j + 1] != str[i]) j = ne[j];
            if(str[j + 1] == str[i]) ++j;
            ne[i] = j;
        }
        
        
        //预处理出A[i][j]
        
        for(int j = 0; j < m; ++j)
            //枚举下一位字符
            for(int c = '0'; c <= '9'; ++c)
            {
                //已经匹配长度
                int k = j;
                //寻找匹配的长度
                while(k && str[k + 1] != c) k = ne[k];
                //找到
                if(str[k + 1] == c) ++k;
                //k < m防止越界
                if(k < m) ++a[j][k];
            }
        
        //F[n] = F[0] * A ^ n
        
        cout << qmi(n) <<endl;
        
        
        return 0;
    }
    
  • 相关阅读:
    学习笔记: yield迭代器
    学习笔记: 委托解析和封装,事件及应用
    学习笔记: MD5/DES/RSA三类加密,SSL协议解析
    学习笔记: Expression表达式目录树详解和扩展封装
    学习笔记: Expression表达式目录树详解和扩展封装
    学习笔记: IO操作及序列化
    数据类型转换
    短路运算(逻辑运算是短路运算中最常见的一种)
    清除浮动
    css初始化
  • 原文地址:https://www.cnblogs.com/pixel-Teee/p/12252891.html
Copyright © 2011-2022 走看看