题目链接:​​http://acm.hdu.edu.cn/showproblem.php?pid=5318​

题意:
给你n种串。,每种无限个,选择m个物品,问你可以组成几种串。
如果a串的后缀和b串的前缀相等,并且长度>=2,则b串可以连在a串后面(注意,不用合并a,b串相同的位置)。

思路:输入的字符串可能有相同的,注意去重。
若s[i],s[j]可以链接,则ok[i][j] = 1 ; 否则为 0 ;

定义dp[i][j] 表示选择i个串,一、以j串结尾的方案数。
则dp[i][j] = dp[i-1][k]*ok[k][j] (1<= k <= n)

res矩阵第一行初使为1,其他为 0 .

代码:

#include <stdio.h>
#include <ctime>
#include <math.h>
#include <limits.h>
#include <complex>
#include <string>
#include <functional>
#include <iterator>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <list>
#include <bitset>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <iostream>
#include <ctime>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <time.h>
#include <ctype.h>
#include <string.h>
#include <string>
#include <assert.h>

using namespace std;

int n, m;
const int MOD = 1000000007;

struct node
{
int ok[55][55];
}is;

node multi(node a, node b)
{
node tmp;
memset(tmp.ok,0,sizeof(tmp.ok));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
for (int k = 1; k <= n; k++)
{
tmp.ok[i][j] += ((long long)a.ok[i][k] * (long long)b.ok[k][j]) % MOD;
tmp.ok[i][j] %= MOD;
}
return tmp;
}

//
char s[100][20];

bool check(int x, int y) //判断是否符合前缀 后缀要求
{
int lenx = strlen(s[x]), leny = strlen(s[y]);
if (lenx == 1 || leny == 1) return false;
for (int i = lenx - 2; i >= 0; i--)
{
int j = 0, ti = i;
while (ti < lenx && j < leny && s[x][ti] == s[y][j]) ti++, j++;
if (ti == lenx) return true;
}
return false;
}

void solve()
{
int tm = m;
node tmp = is, res;
memset(res.ok, 0, sizeof(res.ok));
for (int i = 1; i <= n; i++) res.ok[1][i] = 1;

tm--;
while (tm)
{
if (tm & 1)
res = multi(res,tmp);
tmp = multi(tmp, tmp);
tm >>= 1;
}
int ans = 0;
for (int i = 1; i <= n; i++)
ans = (ans + res.ok[1][i]) % MOD;
printf("%d\n",ans);
}

set<string> vec;

int main()
{
int t;
scanf("%d",&t);
while (t--)
{
memset(is.ok, 0, sizeof(is.ok));
vec.clear();
scanf("%d%d", &n, &m);

for (int i = 1; i <= n; i++)
{
scanf("%s",s[i]);
vec.insert(s[i]);
}
int num = 0;
for (auto &it : vec) strcpy(s[++num],it.c_str());
n = num;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (check(i, j)) is.ok[i][j] = 1;
solve();
}
return 0;
}