点击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(n?1)+FB(n?1)+FC(n?1)+...+FZ(n?1)+Fa(n?1)
FB(n)=FA(n?1)+FB(n?1)+FC(n?1)+...+FZ(n?1)+Fa(n?1)+Fb(n?1)
FC(n)=FA(n?1)+FB(n?1)+FC(n?1)+...+FZ(n?1)+Fa(n?1)+Fb(n?1)+Fc(n?1)
…
FZ(n)=FA(n?1)+FB(n?1)+FC(n?1)+...+FZ(n?1)+Fa(n?1)+Fb(n?1)+Fc(n?1)+...+Fz(n?1)
Fa(n)=FA(n?1)+FB(n?1)+FC(n?1)+...+FZ(n?1)+Fa(n?1)+Fb(n?1)+Fc(n?1)+...+Fz(n?1)
Fb(n)=FB(n?1)+FC(n?1)+...+FZ(n?1)+Fa(n?1)+Fb(n?1)+Fc(n?1)+...+Fz(n?1)
Fc(n)=FC(n?1)+...+FZ(n?1)+Fa(n?1)+Fb(n?1)+Fc(n?1)+...+Fz(n?1)
…
Fz(n)=FZ(n?1)+Fa(n?1)+Fb(n?1)+Fc(n?1)+...+Fz(n?1)
我们设Gc(n) = 有n个字符,第n个字符为c的相邻的两个字符的ASCLL码的绝对值**小于**32的方案数。
那么
GA(n)=GA(n?1)+GB(n?1)+GC(n?1)+...+GZ(n?1)
GB(n)=GA(n?1)+GB(n?1)+GC(n?1)+...+GZ(n?1)+Ga(n?1)
GC(n)=GA(n?1)+GB(n?1)+GC(n?1)+...+GZ(n?1)+Ga(n?1)+Gb(n?1)
…
GZ(n)=GA(n?1)+GB(n?1)+GC(n?1)+...+GZ(n?1)+Ga(n?1)+Gb(n?1)+Gc(n?1)+...+Gy(n?1)
Ga(n)=GB(n?1)+GC(n?1)+...+GZ(n?1)+Ga(n?1)+Gb(n?1)+Gc(n?1)+...+Gz(n?1)
Gb(n)=GC(n?1)+...+GZ(n?1)+Ga(n?1)+Gb(n?1)+Gc(n?1)+...+Gz(n?1)
…
Gz(n)=Ga(n?1)+Gb(n?1)+Gc(n?1)+...+Gz(n?1)
建立变换矩阵,而后高速幂。
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 1000000007struct 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;
}