现在身为校庆志愿者的小C正在引导校友们到他们集合的教室。终于,忙了一段时间的他可以休息一会儿了。这时,旁边一位老校友的话吸引到了他。“我后来当了一名探险家,有一次,我来到了一个地方,在正前方有一扇门,旁边写着一行文字:’现在给你前m个字符串G,有一个拼接规律T,它是一个长度为m的一个排列,你要把现在已经得到的最后m个字符串按照T的顺序拼接起来,得到一个新的字符串,用这种方法,你可得到第n个字符串P,再给你另外一个字符串S,则S在P中出现的次数就是这个门的密码…’”听到这里,小C陷入了沉思:到底密码是多少呢?不过由于小C比较讨厌大数,他只想知道这个密码除以(10^9+7)的余数。你能帮帮他吗?
首先,对于原串内产生的贡献(就是不计算因合并两串而新产生的贡献)容易计算,直接用一个矩阵乘法即可,
考虑因合并两串而新产生的贡献怎么算,
合并两串的贡献只与开头结尾是哪个串有关,其他的可以递推转移,
对于第i个串的开头,它只与第(i-m+b[1]-1)个串的开头有关,
所以开头肯定是有循环的,且循环节最长为n,
结尾也同理,所以它们两合在一起的循环节最长为m*(m-1),
那么就找出这个循环节,再用矩阵快速幂即可,
#include
#include
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
using namespace std;
typedef long long LL;
const int N=205,mo=1e9+7;
int m,n,m1,m2,n1,n2;
LL ans;
int a[10][205];
int b[10],c[N],cx[N];
LL f[N];
LL jz[N][N];
LL jz1[N][N];
int sm[N][N];
map<int,int>Hx;
LL d[N*N*2][4];
void chenj(int n)
{
fo(i,1,n)fo(k,1,n)fo(j,1,n)jz1[i][j]=(jz1[i][j]+jz[i][k]*jz[k][j])%mo;
fo(i,1,n)fo(j,1,n)jz[i][j]=jz1[i][j],jz1[i][j]=0;
}
void chenans(int n)
{
fo(i,1,n)jz1[0][i]=0;
fo(j,1,n)fo(i,1,n)jz1[0][i]=(jz1[0][i]+jz[j][i]*f[j])%mo;
fo(i,1,n)f[i]=jz1[0][i],jz1[0][i]=0;
}
void JZksm(int w,int n)
{
for(;w;w>>=1,chenj(n))if(w&1)chenans(n);
}
int HX(int l)
{
int ans=0;
fo(i,l,l+n-1)ans=ans*n*n+d[i][0]*n+d[i][1];
return ans;
}
int main()
{
freopen("password.in","r",stdin);
freopen("password.out","w",stdout);
int q,w,e;char ch;
scanf("%d",&n);
fo(i,1,n)
{
for(ch=' ';ch<'a'||ch>'z';ch=getchar());
for(q=1;ch<='z'&&ch>='a';ch=getchar(),q++)a[i][q]=ch-96;
}
m=q-1;
fo(i,1,n)scanf("%d",&b[i]);
scanf("%d",&m1);
fo(i,1,m1)
{
memset(jz,0,sizeof(jz));
memset(d,0,sizeof(d));
for(ch=' ';ch<'a'||ch>'z';ch=getchar());
for(m2=1;ch<='z'&&ch>='a';ch=getchar(),m2++)c[m2]=ch-96;
m2--;
scanf("%d",&n1);
q=0;
fo(i,2,m2)
{
while(q&&c[q+1]!=c[i])q=cx[q];
if(c[q+1]==c[i])q++;
cx[i]=q;
}
ans=0;
fo(i,1,n)
{
q=0;
int t=0;
fo(j,1,m)
{
while(q&&c[q+1]!=a[i][j])q=cx[q];
if(c[q+1]==a[i][j])q++;
if(q==m2)q=cx[q],t++;
}
f[i]=t;
}
if(n1>n)
{
fo(i,1,n-1)jz[i+1][i]=1;
fo(i,1,n)jz[i][n]=1;
JZksm(n1-n,n);
ans=f[n];
}else ans=f[n1];
fo(i,1,n)fo(j,1,n)
{
q=0;
fo(k,m-m2+2,m)
{
while(q&&c[q+1]!=a[i][k])q=cx[q];
if(c[q+1]==a[i][k])q++;
}
sm[i][j]=0;
fo(k,1,m2-1)
{
while(q&&c[q+1]!=a[j][k])q=cx[q];
if(c[q+1]==a[j][k])q++;
if(q==m2)q=cx[q],sm[i][j]++;
}
}
Hx.clear();
fo(i,1,n)d[i][0]=d[i][1]=i,d[i][2]=0;
int t=HX(1);
Hx[t]=1;
bool BK=0;
fo(i,n+1,1e9)
{
if(i>n1){ans=(ans+d[i-1][2])%mo;BK=1;break;}
d[i][0]=d[i-n+b[1]-1][0];
d[i][1]=d[i-n+b[n]-1][1];
d[i][2]=d[i-n+b[1]-1][2];
fo(j,2,n)
{
d[i][2]+=d[i-n-1+b[j]][2];
if(d[i][2]>=mo)d[i][2]-=mo;
d[i][3]+=sm[d[i-n-1+b[j-1]][1]][d[i-n-1+b[j]][0]];
if(d[i][3]>=mo)d[i][3]-=mo;
}
d[i][2]+=d[i][3];
if(d[i][2]>=mo)d[i][2]-=mo;
t=HX(i-n+1);
if(Hx[t])
{
t=Hx[t];
if(t+2*n-1>=i)continue;
ans=(ans+d[t-1][2])%mo;
n1-=t-1;
n2=i-t+1-n+1;
fo(j,1,n2-1)f[j]=d[t+j-1][2];
f[n2]=1;
memset(jz,0,sizeof(jz));
int I=i-n;
fo(j,1,n2-1)
{
I++;
if(j>n)
{
d[I][0]=d[I-n-1+b[1]][0];
d[I][1]=d[I-n-1+b[n]][1];
fo(k,2,n)
{
d[I][3]+=sm[d[I-n-1+b[k-1]][1]][d[I-n-1+b[k]][0]];
if(d[I][3]>=mo)d[I][3]-=mo;
}
}
fo(k,n2-n+j-1,n2-1)jz[k][j]++;
fo(k,max(1,j-n),j-1)fo(l,1,n2)
{
jz[l][j]+=jz[l][k];
if(jz[l][j]>=mo)jz[l][j]-=mo;
}
jz[n2][j]+=d[I][3];
if(jz[n2][j]>=mo)jz[n2][j]-=mo;
}
jz[n2][n2]=1;
break;
}else Hx[t]=i-n+1;
}
if(BK){printf("%lld\n",ans);continue;}
JZksm((n1-1)/(n2-1),n2);
if(n1%(n2-1)==0)ans=(ans+f[n2-1])%mo;
else ans=(ans+f[n1%(n2-1)])%mo;
printf("%lld\n",ans);
}
return 0;
}