刷题记录2015.11.20

本文通过两道题目的解析,介绍了使用AC自动机解决字符串匹配问题的方法。BZOJ1009为单一模式串匹配,而POJ2778则是多模式串匹配的加强版。文章提供了完整的代码实现,并详细解释了AC自动机的构造过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BZOJ1009:看了下面那道反过来看这一道还真是有点豁然开朗的感觉。

POJ2778:这题是它的加强版,模式串变成了M个,那么用AC自动机就行了,不过看似简单但是理解AC自动机是一个图的过程还是有些奇妙的。


代码如下:

BZOJ1009:

#include "cstdio"
#include "cstdlib"
#include "iostream"
#include "algorithm"
#include "cstring"
#include "queue"
 
using namespace std;
 
#define MAX_SIZE 50
#define INF 0x3F3F3F3F
#define Eps
#define Mod K
 
inline int Get_Int()
{
    int Num = 0, Flag = 1;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-')
            Flag *= -1;
    }
    while(ch < '0' || ch > '9');
    do
    {
        Num = Num * 10 + ch - '0';
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9');
    return Num * Flag;
}
 
int Next[MAX_SIZE], X[MAX_SIZE];
int N, K, M, Ans;
 
struct Matrix
{
    int A[MAX_SIZE][MAX_SIZE];
    int n, m;
 
    inline Matrix operator * (Matrix const &a) const
    {
        Matrix temp;
        memset(&temp, 0, sizeof(Matrix));
        temp.n = n;
        temp.m = a.m;
        for(int i = 0; i <= temp.n; ++i)
            for(int j = 0; j <= temp.m; ++j)
                for(int k = 0; k <= m; ++k)
                    temp.A[i][j] = (temp.A[i][j] + A[i][k] * a.A[k][j]) % Mod;
        return temp;
    }
 
    inline void operator *= (Matrix const &a)
    {
        *this = (*this) * a;
    }
 
    inline Matrix operator ^ (const int k)
    {
        Matrix ans, K1;
        memset(&ans, 0, sizeof(Matrix));
        K1 = *this;
        ans.n = ans.m = n;
        for(int i = 0; i <= n; ++i)
            ans.A[i][i] = 1;
        int temp = k;
        while(temp)
        {
            if(temp & 1)
                ans *= K1;
            temp >>= 1;
            K1 *= K1;
        }
        return ans;
    }
}a, DP;
 
int main()
{
    cin >> N >> M >> K;
    char ch = getchar();
    while(ch < '0' || ch > '9')
        ch = getchar();
    for(int i = 1; i <= M; ++i)
        X[i] = ch - '0', ch = getchar();
    X[M + 1] = 10;
    int temp = 0;
    for(int i = 2; i <= M; ++i)
    {
        while(temp && X[i] != X[temp + 1])
            temp = Next[temp];
        if(X[i] == X[temp + 1])
            Next[i] = ++temp;
    }
    a.n = a.m = M - 1;
    for(int i = 0; i < M; ++i)
    {
        for(int j = 0; j < 10; ++j)
        {
            int temp = i;
            while(temp && X[temp + 1] != j)
                temp = Next[temp];
            if(X[temp + 1] == j)
                ++temp;
            ++a.A[i][temp];
        }
    }
    DP.A[0][0] = 1;
    DP.n = 0;
    DP.m = M - 1;
    DP *= (a ^ N);
    for(int i = 0; i < M; ++i)
        Ans = (Ans + DP.A[0][i]) % Mod;
    cout << Ans << endl;
    return 0;
}



POJ2778:

#include "cstdio"
#include "cstdlib"
#include "iostream"
#include "algorithm"
#include "cstring"
#include "queue"

using namespace std;

#define MAX_SIZE 105
#define INF 0x3F3F3F3F
#define Eps
#define Mod 100000

inline int Get_Int()
{
	int Num = 0, Flag = 1;
	char ch;
	do
	{
		ch = getchar();
		if(ch == '-')
			Flag *= -1;
	}
	while(ch < '0' || ch > '9');
	do
	{
		Num = Num * 10 + ch - '0';
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9');
	return Num * Flag;
}

class Node
{
public:
	Node *Fail, *Next[4];
	int Num;
	bool Flag;
}*Root, *Empty;

class Matrix
{
public:
	int N, M;
	long long A[MAX_SIZE][MAX_SIZE];

	inline Matrix operator * (Matrix const &a) const
	{
		Matrix temp;
		memset(&temp, 0, sizeof(temp));
		temp.N = N;
		temp.M = a.M;
		for(int i = 1; i <= N; ++i)
			for(int j = 1; j <= temp.M; ++j)
				for(int k = 1; k <= M; ++k)
					temp.A[i][j] = (temp.A[i][j] + A[i][k] * a.A[k][j]) % Mod;
		return temp;
	}

	inline Matrix operator ^ (int k) const
	{
		Matrix a = *this, Ans;
		memset(&Ans, 0, sizeof(Ans));
		Ans.N = Ans.M = N;
		for(int i = 1; i <= N; ++i)
			Ans.A[i][i] = 1;
		while(k)
		{
			if(k & 1)
				Ans = Ans * a;
			k >>= 1;
			a = a * a;
		}
		return Ans;
	}
}A, Ans;

int N, M, Total;

bool Visit[MAX_SIZE];

char Word[MAX_SIZE];

inline Node* New()
{
	Node *x = (Node*)(malloc(sizeof(Node)));
	memset(x, 0, sizeof(Node));
	x -> Num = Total++;
	return x;
}

inline int Get(char ch)
{
	if(ch == 'A')
		return 0;
	else if(ch == 'G')
		return 1;
	else if(ch == 'C')
		return 2;
	else
		return 3;
}

inline void Build_Trie()
{
	Empty = New();
	Root = New();
	for(int i = 0; i < 4; ++i)
		Empty -> Next[i] = Root;
	Root -> Fail = Empty;
	for(int i = 1; i <= M; ++i)
	{
		Node *Now = Root;
		scanf("%s", Word);
		for(int j = 0, temp = strlen(Word), To; j < temp; ++j, Now = Now -> Next[To])
		{
			To = Get(Word[j]);
			if(!Now -> Next[To])
				Now -> Next[To] = New();
		}
		Now -> Flag = true;
	}
}

inline void Build_ACAM()
{
	queue<Node*> Queue;
	Queue.push(Root);
	while(!Queue.empty())
	{
		Node *Now = Queue.front(), *temp;
		Queue.pop();
		if(Now -> Fail -> Flag)
			Now -> Flag = true;
		for(int i = 0; i < 4; ++i)
			if(Now -> Next[i])
			{
				Now -> Next[i] -> Fail = Now -> Fail -> Next[i];
				Queue.push(Now -> Next[i]);
			}
			else
				Now -> Next[i] = Now -> Fail -> Next[i];
	}
}

inline void Get_Matrix()
{
	queue<Node*> Queue;
	Queue.push(Root);
	Visit[Root -> Num] = true;
	while(!Queue.empty())
	{
		Node *Now = Queue.front(), *temp;
		Queue.pop();
		if(Now -> Flag)
			continue;
		for(int i = 0; i < 4; ++i)
		{
			if(Now -> Next[i] -> Flag)
				continue;
			++A.A[Now -> Num][Now -> Next[i] -> Num];
			if(!Visit[Now -> Next[i] -> Num])
			{
				Visit[Now -> Next[i] -> Num] = true;
				Queue.push(Now -> Next[i]);
			}
		}
	}
	A.N = A.M = Total - 1;
}

int main()
{
	cin >> M >> N;
	Build_Trie();
	Build_ACAM();
	Get_Matrix();
	Ans.N = 1;
	Ans.M = Total - 1;
	Ans.A[1][1] = 1;
	Ans = Ans * (A ^ N);
	long long Sum = 0;
	for(int i = 1; i < Total; ++i)
		Sum = (Sum + Ans.A[1][i]) % Mod;
	cout << Sum << endl;
	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值