题意:给出一个字符集和一个字符串s,再给出一个长度n,求出所有以字符集中的字母组成的长度为n的不含s的字符串的数量。
思路:用矩阵ans[i][j]表示当前正在匹配第i个字符转移到下一次匹配第j个字符的方案总数,那么最后的答案就是sigma(ans[0][i]),(0 <= i < strlen(s)),现在的问题就是初始化这个矩阵,很明显这里要用到KMP算法中的next数组,具体方法就是,枚举当前正在匹配的字符的位置i,然后枚举字符集中的所有字符c,这一步代表的含义就是匹配到第i个位置时遇到字符c 要跳到哪个位置j,然后将ans[i][j]++,最后用矩阵快速幂算出长度为n时的情况即可。具体思路见码。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 55;
const int MAXM = 55;
int n, len1, len2;
char str1[MAXN], P[MAXN];
int f[MAXN];
struct Matrix {
int n, m;
unsigned a[MAXN][MAXM];
Matrix() {
memset(a, 0, sizeof(a));
n = m = len2;
for(int i = 0; i < n; i++) a[i][i] = 1;
}
void clear() {
n = m = 0;
memset(a, 0, sizeof(a));
}
Matrix operator * (const Matrix& b) const {
Matrix tmp;
tmp.clear();
tmp.n = n; tmp.m = b.m;
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
for(int k = 0; k < m; k++) tmp.a[i][j] += a[i][k]*b.a[k][j];
return tmp;
}
Matrix operator ^ (int k) {
Matrix ans, tmp = *this;
while(k) {
if(k&1) ans = ans * tmp;
k >>= 1;
tmp = tmp * tmp;
}
return ans;
}
};
void getFail() {
int m = strlen(P);
f[0] = 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;
}
}
int main() {
//freopen("input.txt", "r", stdin);
int T, kase = 0;
cin >> T;
while(T--) {
scanf("%d%s%s", &n, str1, P);
len1 = strlen(str1), len2 = strlen(P);
getFail();
Matrix ans;
ans.clear();
ans.n = ans.m = len2;
for(int i = 0; i < len2; i++) {
for(int j = 0; j < len1; j++) {
int tmp = i;
while(tmp && P[tmp]!=str1[j]) tmp = f[tmp];
if(P[tmp] == str1[j]) tmp++;
ans.a[i][tmp]++;
//cout << tmp << endl;
}
}
ans = ans ^ n;
unsigned ret = 0;
for(int i = 0; i < len2; i++) ret += ans.a[0][i];
printf("Case %d: %u\n", ++kase, ret);
}
return 0;
}