hdu3658 How many words 矩阵递推分析

点击HDU3658

 分析:

题目有两个条件:1.所选的字符串中任意两个相邻字符的ascll码差值不超过32

     2.至少存在一对相邻的的字符ascll码差值等于32.

看到这里需要注意一点。题目说的是ascll码差值不超过32就行,所以只要是32以内的都行。例如,字符b相邻的可以是a~z还要加上B~Z,但是对于字符B来说,就只有A~Z加上a,b.

所一可以求出所有的满足条件1的个数sum,但最终结果肯定比这个小,因为sum里面存在一些串,其中所有相邻的字符ascll差值都小于32,所以要减去着一些串。

即:

我们设Fc(n) = 有n个字符。第n个字符为c的满足条件一方案数; 
那么

FA(n)=FA(n1)+FB(n1)+FC(n1)+...+FZ(n1)+Fa(n1) 
FB(n)=FA(n1)+FB(n1)+FC(n1)+...+FZ(n1)+Fa(n1)+Fb(n1) 
FC(n)=FA(n1)+FB(n1)+FC(n1)+...+FZ(n1)+Fa(n1)+Fb(n1)+Fc(n1) 
… 
FZ(n)=FA(n1)+FB(n1)+FC(n1)+...+FZ(n1)+Fa(n1)+Fb(n1)+Fc(n1)+...+Fz(n1) 
Fa(n)=FA(n1)+FB(n1)+FC(n1)+...+FZ(n1)+Fa(n1)+Fb(n1)+Fc(n1)+...+Fz(n1) 
Fb(n)=FB(n1)+FC(n1)+...+FZ(n1)+Fa(n1)+Fb(n1)+Fc(n1)+...+Fz(n1) 
Fc(n)=FC(n1)+...+FZ(n1)+Fa(n1)+Fb(n1)+Fc(n1)+...+Fz(n1) 
… 

Fz(n)=FZ(n1)+Fa(n1)+Fb(n1)+Fc(n1)+...+Fz(n1)

我们设Gc(n) = 有n个字符,第n个字符为c的相邻的两个字符的ASCLL码的绝对值**小于**32的方案数。 
那么

GA(n)=GA(n1)+GB(n1)+GC(n1)+...+GZ(n1) 
GB(n)=GA(n1)+GB(n1)+GC(n1)+...+GZ(n1)+Ga(n1) 
GC(n)=GA(n1)+GB(n1)+GC(n1)+...+GZ(n1)+Ga(n1)+Gb(n1) 
… 
GZ(n)=GA(n1)+GB(n1)+GC(n1)+...+GZ(n1)+Ga(n1)+Gb(n1)+Gc(n1)+...+Gy(n1) 
Ga(n)=GB(n1)+GC(n1)+...+GZ(n1)+Ga(n1)+Gb(n1)+Gc(n1)+...+Gz(n1) 
Gb(n)=GC(n1)+...+GZ(n1)+Ga(n1)+Gb(n1)+Gc(n1)+...+Gz(n1) 
… 
Gz(n)=Ga(n1)+Gb(n1)+Gc(n1)+...+Gz(n1)

建立变换矩阵,而后高速幂。

ans=i<=zi=AFi(n)i<=zi=AGi(n)

需要注意的是对于F和G的结尾个数不同,自己需要揣测清楚。例如F(Z)与G(Z)是不一样的。

下面配一张图是我写的矩阵:

这张图的左边部分,即f(n-1)(A)......就是所有当字符长度为3时的以A(或其他)结尾的串的个数,左右相乘箭头右边就是当字符长度为4时的所有串的

个数。对于G(n)同理求得。

下面是代码,如果还不理解,可以试试我的代码,用里面的print()函数,输出初始化后的N1与N2分析。

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 52
#define me(x) memset(x,0,sizeof(x))
#define ll long long
#define mod 1000000007

struct mat//用结构体封装矩阵
{
    ll m[maxn][maxn];
}unit,G,F,N1,N2;

void init()//初始化
{
    me(unit.m);
    me(G.m);
    me(F.m);
    me(N1.m);me(N2.m);
    for(int i=0;i<26;i++)//单行
    {
        F.m[i][0]=27+i;
        G.m[i][0]=F.m[i][0]-1;
        unit.m[i][i]=1;
    }

    for(int i=26,j=0;i<52;i++,j+=2)//单行
    {
        F.m[i][0]=26+(i-j);
        G.m[i][0]=F.m[i][0]-1;
        unit.m[i][i]=1;
    }

    for(int i=0;i<52;i++)
    {
        unit.m[i][i]=1;
    }

    for(int i=0;i<26;i++)
    {
        for(int j=0;j<=i+26;j++)
        {
            N1.m[i][j]=1;
        }
    }
    for(int i=26;i<52;i++)
    {
        for(int j=51;j>=i-26;j--)
        {
             N1.m[i][j]=1;
        }
    }
     for(int i=0;i<26;i++)
    {
        for(int j=0;j<=i+25;j++)
        {
            N2.m[i][j]=1;
        }
    }
    for(int i=26;i<52;i++)
    {
        for(int j=51;j>i-26;j--)
        {
             N2.m[i][j]=1;
        }
    }
}

void print(mat a)//自己写的打印函数
{
    int i,j;
    for(i=0;i<maxn;i++)
    {
        for(j=0;j<maxn;j++)
            printf("%d ",a.m[i][j]);
        puts("");
    }
    puts("");
    return ;
}

mat operator*(mat a,mat b)//对*运算符重载为矩阵相乘
{
    mat p;
    for(int i=0;i<maxn;i++)
    {
        for(int j=0;j<maxn;j++)
        {
            p.m[i][j]=0;
            for(int w=0;w<maxn;w++)
            {
                p.m[i][j]+=a.m[i][w]*b.m[w][j]%mod;
                p.m[i][j]%=mod;
            }
        }
    }
    return p;
}

ll pow(mat N,int k,mat p)//矩阵快速幂
{
    mat ans;
    ll sum=0;
    ans=unit;

    while(k)
    {
        if(k&1)
        {
            ans=ans*N;
        }
        N=N*N;
        k=k>>1;
    }
    ans=ans*p;
   for(int i = 0 ; i < maxn ; i++)
    {
        for(int j=0;j <maxn;j++)
        {
            sum += ans.m[i][j];
           // cout<<sum<<endl;
        }
        sum %= mod;
    }

    return sum%mod;//因为ans[0][0]就是f(n);
}

int main()
{
    init();

    /*/cout<<3<<endl;
    print(N1);
    cout<<4<<endl;
    print(N2);
    cout<<5<<endl;
    print(unit);*/
    int n,t;
    scanf("%d",&t);
    long long cnt;
    while(t--)
    {
        init();
        scanf("%d",&n);
        if(n==2) cout<<52<<endl;
        else
        {
            //cout<<pow(N1,n-1,F)<<" "<<pow(N2,n-1,G)<<endl;
            cnt=((pow(N1,n-2,F)-pow(N2,n-2,G))+mod)%mod;
            cout<<cnt%mod<<endl;
        }
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章