POJ 4052 Hrinity 解题报告

题目

题意:

有一些压缩模式串和压缩主串,展开后问有多少个模式串在主串里,注意若两个模式串都在主串内,且一个包含另一个,则只算一次。

解法:

展开后,用模式串建AC自动机,然后用主串跑一次看有哪些包含在内,然后将模式串连在一次,再跑一次看有哪些包含,然后减去就可以啦。

TIme:469ms
Memory:47836KB
Length:3327B
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <queue>
#include <set>
#define PI 3.1415926535898
#define INF 1000000000
#define MAXM 300010
#define MP(x,y) (make_pair((x),(y)))
using namespace std;
struct Node{
	int cnt,h,len;
	int next[27],fail;
	void init()
	{
		h=0;
		cnt = 0;
		fail = -1;
		memset(next,-1,sizeof(next));
	}
}trie[MAXM];
char str[5100005],tstr[5100005],sub[2505*1205];
int cnt,ans,subl,pos[2505],total;
vector<int> tpos,tcnt;
short ssub[2505*1205];
bool vi[2505];
void insert(char str[],int h)
{
	int p=0,x;
	for(int i=0;str[i];i++)
	{
		x=str[i]-'A';
		if(trie[p].next[x]==-1)
		{
			trie[++cnt].init();
			trie[p].next[x]=cnt;
		}
		p=trie[p].next[x];
	}
	trie[p].cnt++;
	trie[p].h=h;
	trie[p].len=strlen(str);
	pos[h]=p;
}
void build_ac()
{
	queue<int> q;
	int root=0;
	q.push(0);
	while(!q.empty())
	{
		int p=q.front();
		int temp=0;
		q.pop();
		for(int i=0;i<26;i++)
		{
			int child=trie[p].next[i];
			if(child!=-1)
			{
				if(p==root)
					trie[child].fail=root;
				else
				{
					temp=trie[p].fail;
					while(temp!=-1)
					{
						if(trie[temp].next[i]!=-1)
						{
							trie[child].fail=trie[temp].next[i];
							break;
						}
						temp=trie[temp].fail;
					}
					if(temp==-1)
						trie[child].fail=root;
				}
				q.push(child);
			}
		}
	}
}
int query(char str[],int ty)
{
	int index,len,result,root=0;
	int p=root;
	result=0;
	len=strlen(str);
	for(int i=0;i<len;i++)
	{
		index=str[i]-'A';
		while(trie[p].next[index]==-1&&p!=root)
			p=trie[p].fail;
		p=trie[p].next[index];
		if(p==-1)
			p=root;
		int temp=p;
		while(temp!=root&&trie[temp].cnt!=-1)
		{
			result+=trie[temp].cnt;
			bool flag=0;
			if(ty==0)
			{
				int tt=i-trie[temp].len+1;
				if(tt>=0&&ssub[tt]==ssub[i]&&ssub[tt]!=trie[temp].h&&vi[ssub[tt]]==1)
				{
				    if(trie[temp].h&&vi[trie[temp].h])
                        vi[trie[temp].h]=0,--total;
				}
                else    flag=1;
			}
            tpos.push_back(temp);
            tcnt.push_back(trie[temp].cnt);
			if(flag==0)
                trie[temp].cnt=-1;
            if(ty==1)
                vi[trie[temp].h]=1;

			temp=trie[temp].fail;
		}
	}
	return result;
}
void change(char tstr[])
{
	int j = 0;
	for(int i = 0;tstr[i];i++)
	{
		if(tstr[i]>='A'&&tstr[i]<='Z') str[j++]=tstr[i];
		else if(tstr[i]=='[')
		{
			int num = 0;
			while(tstr[++i]>='0'&&tstr[i]<='9')
			{
				num = num*10+tstr[i]-'0';
			}
			char tmp;
			for(;tstr[i]!=']';i++) tmp = tstr[i];
			for(int k = 0; k < num;k++)
				str[j++]=tmp;
		}
	}
	str[j]='\0';
}
void add(char s[],int h)
{
	for(int i=0;s[i];++i,++subl)
		sub[subl]=s[i],ssub[subl]=h;
}
int main()
{
    //freopen("J:\\MyDocument\\Code\\input.txt","r",stdin);
	int ca,n;
	scanf("%d",&ca);
	while(ca--)
	{
		subl=0;
		trie[0].init();
		scanf("%d",&n);
		cnt = 0;
		for(int i = 0; i < n; i++)
		{
			scanf("%s",tstr);
			change(tstr);
			add(str,i+1);
			insert(str,i+1);
		}
		build_ac();
		tpos.clear(),tcnt.clear();
		memset(vi,0,sizeof(vi));
		scanf("%s",tstr);
		change(tstr);
		total=query(str,1);
		for(int i=0;i<tpos.size();++i)
            trie[tpos[i]].cnt=tcnt[i];
        sub[subl]='\0';
        query(sub,0);
        printf("%d\n",total);
	}
}


你可能感兴趣的:(POJ 4052 Hrinity 解题报告)