procedure2012
It's not worth it to know you're not worth it!

[关键字]:动态规划 矩阵乘法

[题目大意]:给定一个字符集为(0-9)的字符串T(length<=20),求长度为N的不包含T的字符串的总数。

//==========================================================================

[分析]:首先可以用KMP求next数组的方法求出f[i][j],T串的前i个字符组成的一个串+任意一个字符的后j位和T的前j各字符匹配的方案数。把这个数组乘n遍后f[0][i]就是T的前0

个加上n个字符后i为和T前i位匹配的方案数。ans=Σf[0][i](0<=i<=m-1)。而f数组的n次方可以用快速幂加矩阵乘法快速解决。

[代码]:

View Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;

const int MAXN=30;

int n,m,MOD;
int a[MAXN],p[MAXN];
int temp[MAXN][MAXN],temp2[MAXN][MAXN];
int b[MAXN][MAXN],f[MAXN][MAXN];

void Init()
{
     scanf("%d%d%d\n",&n,&m,&MOD);
     for (int i=1;i<=m;++i) scanf("%c",&a[i]),a[i]-='0';
     //for (int i=1;i<=m;++i) printf("%d ",a[i]);
}

void KMP()
{
     int k=0;
     p[1]=0;
     for (int i=2;i<=m;++i)
     {
         while (k>0 && a[i]!=a[k+1]) k=p[k];
         if (a[i]==a[k+1]) ++k;;
         p[i]=k;
     }
}

void Work()
{
     memset(b,0,sizeof(b));
     for (int i=0;i<m;++i)
         for (int j=0;j<=9;++j)
         {
             int k=i;
             while (k>0 && a[k+1]!=j) k=p[k];
             if (a[k+1]==j) ++b[i][k+1]; else ++b[i][0];
         }
     memcpy(f,b,sizeof(b));
}

void Power(int n)
{
     if (n==1) return;
     Power(n/2);
     memset(temp,0,sizeof(temp));
     for (int i=0;i<m;++i)
         for (int j=0;j<m;++j)
             for (int k=0;k<m;++k)
                 temp[i][j]=(temp[i][j]+f[i][k]*f[k][j])%MOD;
     memcpy(f,temp,sizeof(f));                 
     if (n%2==1)
     {
                memset(temp2,0,sizeof(temp2));
                for (int i=0;i<m;++i)
                    for (int j=0;j<m;++j)
                        for (int k=0;k<m;++k)
                            temp2[i][j]=(temp2[i][j]+temp[i][k]*b[k][j])%MOD;
                memcpy(f,temp2,sizeof(f));
     }
}

void Solve()
{
     KMP();
     //for (int i=1;i<=m;++i) printf("%d ",p[i]);
     //printf("\n");
     Work();
     /*for (int i=0;i<m;++i)
     {
         for (int j=0;j<m;++j) printf("%d ",f[i][j]);
         printf("\n");
     }*/
     Power(n);
     /*for (int i=0;i<m;++i)
     {
         for (int j=0;j<m;++j) printf("%d ",f[i][j]);
         printf("\n");
     }*/
     int sum=0;
     for (int i=0;i<m;++i) sum=(sum+f[0][i])%MOD;
     printf("%d\n",sum);
}

int main()
{
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    Init();
    //for (int i=1;i<=m;++i) printf("%d ",a[i]);
    //printf("\n");
    Solve();
    return 0;
}



posted on 2012-04-07 00:07  procedure2012  阅读(1167)  评论(0编辑  收藏  举报