题目来源:Light OJ 1268 Unlucky Strings
题意:给你一些可以用的字符 然后求组成不包含给定字符串的方案数
思路:矩阵经典问题 从i走k步路到达j的方案数 可以用矩阵快速幂求解
对于求长度为n的字符的方案数 就是走n步路 求走法
可以用KMP求出走一步 从前i个字符到前j个字符的方案数 这点有点不好理解 想一想
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 55;
typedef unsigned int LL;
struct Mat
{
LL a[maxn][maxn];
};
Mat A, B;
int f[maxn];
void getFail(char *p)
{
int m = strlen(p);
f[0] = f[1] = 0;
for(int i = 1; i < m; i++)
{
int j = f[i];
while(j && p[i] != p[j])
j = f[j];
f[i+1] = p[i] == p[j] ? j+1 : 0;
}
}
void find(int i, char c, char* p)
{
int j = i;
while(j && c != p[j])
j = f[j];
if(c == p[j])
j++;
A.a[i][j]++;
}
Mat get(Mat x, Mat y, int l)
{
Mat z;
memset(z.a, 0, sizeof(z.a));
for(int i = 0; i < l; i++)
for(int j = 0; j < l; j++)
for(int k = 0; k < l; k++)
{
z.a[i][j] += x.a[i][k]*y.a[k][j];
//z.a[i][j] %= mod;
}
return z;
}
void Mat_pow(int n, int l)
{
if(n <= 0)
return;
while(n)
{
if(n&1)
B = get(A, B, l);
A = get(A, A, l);
n >>= 1;
}
}
int main()
{
int cas = 1;
int T;
scanf("%d", &T);
while(T--)
{
int n;
scanf("%d", &n);
char s1[55], s2[55];
scanf("%s %s", s1, s2);
getFail(s2);
memset(A.a, 0, sizeof(A.a));
memset(B.a, 0, sizeof(B.a));
int l1 = strlen(s1);
int l2 = strlen(s2);
for(int i = 0; i < l2; i++)
{
for(int j = 0; j < l1; j++)
{
find(i, s1[j], s2);
}
B.a[i][i] = 1;
}
Mat_pow(n, l2);
LL ans = 0;
for(int i = 0; i < l2; i++)
ans += B.a[0][i];
printf("Case %d: %u\n", cas++, ans);
}
return 0;
}