分析:
题目有两个条件: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 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;
}