首页 > 代码库 > Light OJ 1268 Unlucky Strings 矩阵快速幂+KMP

Light OJ 1268 Unlucky Strings 矩阵快速幂+KMP

题目来源: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;
}