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;
}


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