• 【BZOJ 1009】 [HNOI2008]GT考试


    【题目链接】:http://www.lydsy.com/JudgeOnline/problem.php?id=1009

    【题意】

    【题解】

    网上有几个博客写得挺好的.
    这里发一下链接;
    这一篇有把大概怎么做写下来;
    http://www.cnblogs.com/BLADEVIL/p/3483694.html
    而下面这一篇提到的细节比较好;也讲得比较清楚些;
    http://blog.csdn.net/cjk_cjk/article/details/43038377
    大概的思路:
    假设你现在扫描到了你的准考证号的第i位,同时不吉利数字匹配到了第j位;
    也就是说准考证上:i-j+1..i和不吉利数字的1..j匹配好了;
    接下来要确定第i+1位是什么;
    这里把第i+1位换成第i位,原来的第i位就变成i-1位;
    设f[i][j]表示:准考证号前i位中 后j位与不吉利数的前j位相同时,前i位的方案数
    则有
    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]
    这里的a[k][j]表示的是前一位如果匹配到了第k位,然后想通过增加一个数字变成i个数字 ,然后匹配到第j位,问在第i位有多少个数字可以选择;
    这个a数组可以预处理出来;
    我们先考虑这个a数组的求法:
    比如不吉利数字为
    1231243
    这里;
    假设我们扫描到了第5个数字2;
    那么我们就相当于让第i-1个数字匹配到了第5个数字;
    然后问你第i个状态哪些状态能由这第5个数字接受到?
    它的下一个状态应该可以接匹配到了第3和第6个数字;
    即类似
    *****12x
    ****12312x
    可能用上面博客的例子好一点:
    比如:还是假设不吉利数为123124,那么
    f[i][3]=f[i-1][2]+f[i-1][5],因为 f[i-1][2]末尾的*****12不能是**12312,所以需要f[i-1][5]补充 ;
    这里的”不能是**12312“可以用一个判重的东西搞出来;
    那么像上面这样的a数组要怎么搞呢?
    KMP算法!
    具体的只能看程序了;
    (你需要理解KMP算法的思路才能搞,不然会看得晕头转向);
    然后N这么大;
    你肯定得写个矩阵快速幂啦;
    主要是因为a数组能够独立出来;
    因为系数确定了;
    所以能够用矩阵;
    以后看到这种线性齐次递推式
    都能写个矩阵优化;
    (我也不知道线性齐次递推式是什么);
    f[0][0]=1,f[0][1..m]=0;
    最后把f[0][0..m-1]加起来就是答案了;
    因为不能全部匹配到嘛.
    下面这一段感觉写得很好吧。

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


    【完整代码】

    #include <bits/stdc++.h>
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define LL long long
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define rei(x) scanf("%d",&x)
    #define rel(x) scanf("%lld",&x)
    
    typedef pair<int,int> pii;
    typedef pair<LL,LL> pll;
    
    const int dx[9] = {0,1,-1,0,0,-1,-1,1,1};
    const int dy[9] = {0,0,0,-1,1,-1,1,-1,1};
    const double pi = acos(-1.0);
    const int M = 30;
    
    struct juzhen
    {
        int s[M][M];
        juzhen()
        {
            memset(s,0,sizeof s);
        }
    };
    
    int n,m,mod,f[M],cf[300];
    char s[M];
    juzhen a,F;
    
    juzhen cheng(juzhen A,juzhen B)
    {
        juzhen c;
        rep1(i,0,m)
            rep1(j,0,m)
                rep1(k,0,m)
                    c.s[i][j] = (c.s[i][j]+A.s[i][k]*B.s[k][j])%mod;
        return c;
    }
    
    juzhen ksm(juzhen A,int n)
    {
        if (n==1)
            return A;
        juzhen res = ksm(A,n>>1);
        juzhen t = cheng(res,res);
        if (n&1)
            t = cheng(t,A);
        return t;
    }
    
    int main()
    {
        //freopen("F:\rush.txt","r",stdin);
        rei(n),rei(m),rei(mod);
        scanf("%s",s+1);
    
        f[1] = f[2] = 1;
        rep1(i,2,m-1)
        {
            int j = f[i];
            while (j > 1 && s[i]!=s[j]) j = f[j];
            f[i+1] = (s[i]==s[j])?j+1:1;
        }
    
        int sum;
        rep1(i,0,m-1)
        {
            int j = i+1;
            sum = a.s[i][j] = 1;
            cf[s[j]] = i+1;
            while (j > 1)
            {
                j = f[j];
                if (cf[s[j]]!=i+1)
                {
                    cf[s[j]] = i+1;
                    a.s[i][j] = 1;
                    sum++;
                }
            }
            a.s[i][0] = 10-sum;
        }
    
        F.s[0][0] = 1;
        F = cheng(F,ksm(a,n));
    
        int ans = 0;
        rep1(i,0,m-1)
            ans = (ans + F.s[0][i])%mod;
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    为什么叫"鲁棒"图
    Linux系统信息查看命令......
    網頁配色工具
    java基础方面知识点
    網頁設計收藏站70個
    bj_linux...
    工具
    软件工程阅读(中英文对照)之软件维护
    软件工程新方法和技术简介(英文)
    软件工程阅读(中英文对照)之文档技术
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626612.html
Copyright © 2020-2023  润新知