题意:
题目很长,但也只有后面有用
给你n(<=50)个串,每个串长度<=10(其实也是不超过1e9的正整数)。如果a串的后缀和b串的前缀相等,并且长度>=2,则b串可以连在a串后面(注意,不用合并a,b串相同的位置)。
每个串的个数都是无穷个,现在让你选m(<=1e9)个串,问你有多少个不同的串(不是有多少个不同长度的串= =)。
11 111
111 11
上面两个串并不相同,因此算两个。
分析:
首先建立一个递推关系
串1:123456 串2:456789 串3:5612
如果此刻递推到第i位,则 dp[i][1]=dp[i-1][2]+dp[i-1][3]
即 dp[i][j]=∑dp[i-1][与j形成链接关系的串的编号]
由于i的范围可到1e9,这时候需要矩阵快速幂了
如样例
5 50
121 123 213 132 321
建立关系矩阵
G[i][j]==1表示串i可以接在串j后面。G[3][1]=1,串3可以接在串1后面
因此,dp[i][j]=∑dp[i-1][k]*G[j][k]
最终结果为dp[m][x](x从0到n)的和。
特别注意:一定要记得去重,这个被坑了无数次
#include<vector>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iostream>
#define INF 0x3f3f3f3f
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define MT(x,i) memset(x,i,sizeof(x))
using namespace std;
typedef long long LL;
const int mod = 1000000007;
const int MAX = 55;
int n,m,G[55][55],S[55];
char s[55][15];
struct Matrix{
LL mat[55][55];
} a,b;
int sz;
void init()
{
sort(S,S+n);
n = unique(S, S + n) - S;
sz = n;
///以上去重
for(int i=0;i<n;i++)///将输入的S数字转成char[]的s数组
sprintf(s[i],"%d",S[i]);
///以下求G矩阵,暴力判断每对串的前缀后缀即可
MT(G,0);
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
{
int li=strlen(s[i]),lj=strlen(s[j]),flag=0;
int l=min(li,lj);
for(int k=2; k<=l; k++){
int f=1;
for(int x=li-k,y=0; y<k; x++,y++)
if(s[i][x]!=s[j][y]){f=0;break;}
if(f){flag=1;break;}
}
if(flag)G[j][i]=1;///j可以接在i后面
}
}
///快速幂模板
Matrix mul(Matrix a,Matrix b)
{
Matrix ret;
for(int i=0; i<sz; i++)
for(int j=0; j<sz; j++)
{
ret.mat[i][j]=0;
for(int k=0; k<sz; k++)
ret.mat[i][j] = (ret.mat[i][j] + (a.mat[i][k]*b.mat[k][j])%mod)%mod;
}
return ret;
}
Matrix pow_M(Matrix aa,LL nn)
{
Matrix ret;
memset(ret.mat,0,sizeof(ret.mat));
for(int i=0; i<sz; i++)ret.mat[i][i]=1;
Matrix temp=aa;
while(nn)
{
if(nn&1)ret=mul(ret,temp);
temp=mul(temp,temp);
nn>>=1;
}
return ret;
}
void show(Matrix a)
{
printf("=======show========\n");
for(int i=0; i<sz; i++)
{
for(int j=0; j<sz; j++)
printf("%d ",a.mat[i][j]);
printf("\n");
}
}
///快速幂模板
int main()
{
int T;
for(scanf("%d",&T); T--;)
{
MT(a.mat,0); MT(b.mat,0);
scanf("%d%d",&n,&m);
for(int i=0; i<n; i++)scanf("%d",&S[i]);
if(n==0||m==0) {printf("0\n");continue;} ///特判
init();
for(int i=0; i<n; i++) a.mat[i][0] = 1;///当m为1时,每个串都可以
//show(a);
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
if(G[i][j]) b.mat[i][j] = 1;///b数组就是G数组,转成模板可用的类型
//show(b);
Matrix temp = pow_M(b,m-1);///矩阵快速幂
temp = mul(temp,a);///
LL ans = 0;
for(int i=0; i<n; i++)
ans = (ans+temp.mat[i][0])%mod; /// 累加dp[m][i]
printf("%I64d\n",ans);
}
return 0;
}