POJ 1625 Censored!

本文介绍了一种解决模式匹配问题的方法,通过构建AC自动机并结合高精度动态规划求解不含特定模式串的字符串数量。文章详细展示了AC自动机的构造过程、状态转移矩阵的建立及高精度DP的状态转移过程。

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

给定p个模式串,求长度为m<=50的串中不包含任何模式串的串的种类数,字符仅由给出的n个字符构成,用mp数组标记下。然后和之前的几道类似,利用end和next数组得到转态转移数组,然后由于题目数据不像之前的那么大,可以用dp[i][j]来进行状态转移,i代表当前串长度,j为当前状态。但是由于答案很大需要用到高精度。代码如下
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;

int N;
int mp[300];

struct Matrix
{
    long long mat[110][110];
    int n;
    Matrix(){}
    Matrix(int _n)
    {
        n=_n;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                mat[i][j] = 0;
    }
    Matrix operator *(const Matrix &b)const
    {
        Matrix ret = Matrix(n);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                for(int k=0;k<n;k++)
                    ret.mat[i][j]+=mat[i][k]*b.mat[k][j];
        return ret;
    }
};
struct Tree
{
	int next[110][256],end[110],fail[110];
	int L,root;
	int newnode()
	{
		for(int i=0;i<255;i++)
		{
			next[L][i]=-1;
		}
		end[L++]=0;
		return L-1;
	}
	void init()
	{
		L=0;
		root=newnode();
	}
	void insert(char *s)
	{
		int len=strlen(s);
		int p=root;
		for(int i=0;i<len;i++)
		{
			if(next[p][mp[s[i]]]==-1)
			{
				next[p][mp[s[i]]]=newnode();
			}
			p=next[p][mp[s[i]]];
		}
		end[p]++;
	}
	void build()
	{
		queue<int>q;
		int p=root;
		fail[root]=root;
		for(int i=0;i<255;i++)
		{
			if(next[p][i]==-1)
			{
				next[p][i]=root;
			}
			else
			{
				fail[next[p][i]]=root;
				q.push(next[p][i]);
			}
		}
		while(!q.empty())
		{
			p=q.front();
			q.pop();
			if(end[fail[p]]) end[p]=1;
			for(int i=0;i<255;i++)
			{
				if(next[p][i]==-1)
				{
					next[p][i]=next[fail[p]][i];
				}
				else
				{
					fail[next[p][i]]=next[fail[p]][i];
					q.push(next[p][i]);
				}
			}
		}
	}
	void query(char *s)
	{
		int len=strlen(s);
		int p=root,ans=0;
		for(int i=0;i<len;i++)
		{
			int id=s[i]-'a';
			p=next[p][id];
			int temp=p;
			while(temp!=root)
			{
				if(end[temp])
				{
					ans+=end[temp];
					end[temp]=0;
				}
				temp=fail[temp];
			}
		}
	}
	Matrix getMatrix()
	{
		Matrix a(L);
		for(int i=0;i<a.n;i++)
		{
			for(int j=0;j<N;j++)
			{
				if(end[next[i][j]]==0)
				a.mat[i][next[i][j]]++;
			}
		}
		return a;
	}
	void debug()
    {
        for(int i = 0;i < L;i++)
        {
            printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
            for(int j = 0;j < 26;j++)
                printf("%2d",next[i][j]);
            printf("]\n");
        }
    }
};

struct BigInt
{
    const static int mod = 10000;
    const static int DLEN = 4;
    int a[600],len;
    BigInt()
    {
        memset(a,0,sizeof(a));
        len = 1;
    }
    BigInt(int v)
    {
        memset(a,0,sizeof(a));
        len = 0;
        do
        {
            a[len++] = v%mod;
            v /= mod;
        }while(v);
    }
    BigInt(const char s[])
    {
        memset(a,0,sizeof(a));
        int L = strlen(s);
        len = L/DLEN;
        if(L%DLEN)len++;
        int index = 0;
        for(int i = L-1;i >= 0;i -= DLEN)
        {
            int t = 0;
            int k = i - DLEN + 1;
            if(k < 0)k = 0;
            for(int j = k;j <= i;j++)
                t = t*10 + s[j] - '0';
            a[index++] = t;
        }
    }
    BigInt operator +(const BigInt &b)const
    {
        BigInt res;
        res.len = max(len,b.len);
        for(int i = 0;i <= res.len;i++)
            res.a[i] = 0;
        for(int i = 0;i < res.len;i++)
        {
            res.a[i] += ((i < len)?a[i]:0)+((i < b.len)?b.a[i]:0);
            res.a[i+1] += res.a[i]/mod;
            res.a[i] %= mod;
        }
        if(res.a[res.len] > 0)res.len++;
        return res;
    }
    BigInt operator *(const BigInt &b)const
    {
        BigInt res;
        for(int i = 0; i < len;i++)
        {
            int up = 0;
            for(int j = 0;j < b.len;j++)
            {
                int temp = a[i]*b.a[j] + res.a[i+j] + up;
                res.a[i+j] = temp%mod;
                up = temp/mod;
            }
            if(up != 0)
                res.a[i + b.len] = up;
        }
        res.len = len + b.len;
        while(res.a[res.len - 1] == 0 &&res.len > 1)res.len--;
        return res;
    }
    void output()
    {
        printf("%d",a[len-1]);
        for(int i = len-2;i >=0 ;i--)
            printf("%04d",a[i]);
        printf("\n");
    }
};

Tree ac;
char s[55];
BigInt dp[2][110];
int main()
{
	int m,p;
	while(~scanf("%d %d %d",&N,&m,&p))
	{
		scanf("%s",s);
		for(int i=0;i<N;i++)
		mp[s[i]]=i;
		ac.init();
		for(int i=0;i<p;i++)
		{
			scanf("%s",s);
			ac.insert(s);
		}
		ac.build();
		Matrix a=ac.getMatrix();
		int now=0;
		dp[now][0]=1;
		for(int i=1;i<a.n;i++)
		{
			dp[now][i]=0;
		}
		for(int i=0;i<m;i++)
		{
			now^=1;
			for(int j=0;j<a.n;j++)
			{
				dp[now][j]=0;
			}
			for(int j=0;j<a.n;j++)
			{
				for(int k=0;k<a.n;k++)
				{
					if(a.mat[j][k]>0)
					{
						dp[now][k]=dp[now][k]+dp[now^1][j]*a.mat[j][k];
					}
				}
			}
		}
		BigInt ans=0;
		for(int i=0;i<a.n;i++)
		{
			ans=ans+dp[now][i];
		}
		ans.output();
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值