HDOJ 题目4787 GRE Words Revenge(在线ac自动机,离线也可做)

GRE Words Revenge

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others)

Total Submission(s): 1570    Accepted Submission(s): 352

Problem Description

  Now Coach Pang is preparing for the Graduate Record Examinations as George did in 2011. At each day, Coach Pang can:

  "+w": learn a word w

  "?p": read a paragraph p, and count the number of learnt words. Formally speaking, count the number of substrings of p which is a learnt words.

  Given the records of N days, help Coach Pang to find the count. For convenience, the characters occured in the words and paragraphs are only ‘0‘ and ‘1‘.

Input

  The first line of the input file contains an integer T, which denotes the number of test cases. T test cases follow.

  The first line of each test case contains an integer N (1 <= N <= 105), which is the number of days. Each of the following N lines contains either "+w" or "?p". Both p and w are 01-string in this problem.

  Note that the input file has been encrypted. For each string occured, let L be the result of last "?" operation. The string given to you has been shifted L times (the shifted version of string s1s2 ... sk is sks1s2 ...
sk-1). You should decrypt the string to the original one before you process it. Note that L equals to 0 at the beginning of each test case.

  The test data guarantees that for each test case, total length of the words does not exceed 105 and total length of the paragraphs does not exceed 5 * 106.

Output

  For each test case, first output a line "Case #x:", where x is the case number (starting from 1).

  And for each "?" operation, output a line containing the result.

Sample Input

2
3
+01
+01
?01001
3
+01
?010
?011

Sample Output

Case #1:
2
Case #2:
1
0

Source

2013 Asia Chengdu Regional Contest

Recommend

We have carefully selected several similar problems for you:  5368 5367 5366 5365 5364

题目大意:+w表示学了一个单词,?p问学了单词的数量(第一,单词是不同的,第二,算的是所有在串中出现的数量,不是存在的单词的数量)

题意确实开始理解错了,

例如

+10

+10

?101

应该是1

+10

?101010

应该是3

然后文字是加密的,上一个求出的值,后边的字符串有像左移这么多位,不管是+还是?的!!!

思路:开始就像用暴力点的,离线做,直接就是模板,,一直re,因为重插入了之后又要重新build_ac一回,确实暴力了点,后来百度看人家都是都是用两个ac自动机实现的在线ac自动机,然后就学了一下,大概思想是这样的就是设两个的ac自动机,一个大的一个小的,小的就相当于缓存,先往小的存。小的有个上限(上限应该是最大节点数的开方,,不过我试了几个数发现差不太多),达到上限之后就往大的ac自动机上合并,合并比较经典。。。具体看代码,,,就这样实现在线查询,,,在修改在线的代码是,发现shift函数写错了,,改过了就过,突然想起来离线的代码可能就是因为这个re的,,然后改了之后wa了,,没超时,,顿时激动了,,改了改也过了,,哈哈,离线也能做

ac代码(在线ac自动机)

注释的那种写法也行算vis

ac代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#pragma comment(linker, "/STACK:1024000000,1024000000")
char str[5000100],s1[5000100];
int head,tail;
int node_num;
struct node
{
    node *fail;
    node *next[2];
    __int64 vis,key;
    node()
    {
        fail=NULL;
        key=vis=0;
        for(int i=0;i<2;i++)
            next[i]=NULL;
    }
}*q[8008000];
node *root1,*root2;
void insert(char *s,node *root)
{
    int temp,len,i;
    node *p=root;
    len=strlen(s);
    for(i=0;i<len;i++)
    {
        temp=s[i]-'0';
        if(p->next[temp]==NULL)
		{
			node_num++;
            p->next[temp]=new node();
		}
        p=p->next[temp];
    }
    p->vis=1;
}
void build_ac(node *root)
{
	head=tail=0;
    q[tail++]=root;
    while(head!=tail)
    {
        node *p=q[head++];
        node *temp=NULL;
        for(int i=0;i<2;i++)
        {
            if(p->next[i]!=NULL)
            {
                if(p==root)
				{
                    p->next[i]->fail=root;
					p->next[i]->key=p->next[i]->vis;
				}
                else
                {
                    temp=p->fail;
                    while(temp!=NULL)
                    {
                        if(temp->next[i]!=NULL)
                        {
                            p->next[i]->fail=temp->next[i];
							p->next[i]->key=temp->next[i]->key+p->next[i]->vis;
                            break;
                        }
                        temp=temp->fail;
                    }
                    if(temp==NULL)
                    {
                        p->next[i]->fail=root;
						p->next[i]->key=p->next[i]->vis;
                    }
                }
                q[tail++]=p->next[i];
            }
        }
    }
}
__int64 query(char *str,node *root)
{
    __int64 ans=0;
    int len=strlen(str);
    node *p=root,*temp;
    for(int i=0;i<len;i++)
    {
        int x=str[i]-'0';
        while(p->next[x]==NULL&&p!=root)
            p=p->fail;
        p=p->next[x];
        if(p==NULL)
        {
            p=root;
        }
        temp=p;
       /*while(temp!=root)
        {
            ans+=temp->vis;
            temp=temp->fail;
       } */
		ans+=temp->key;
    }
    return ans;
}
int seach(char *s,node *root)
{
	int len=strlen(s),i,j,now;
	node *cur=root;
	for(i=0;i<len;i++)
	{
		now=s[i]-'0';
		if(cur->next[now]!=NULL)
		{
			cur=cur->next[now];
		}
		else
			return 0;
	}
	if(cur->vis)
		return 1;
	return 0;
}
void del(node *root)
{
	if(root==NULL)
		return;
	int i;
	for(i=0;i<2;i++)
	{
		if(root->next[i]!=NULL)
			del(root->next[i]);
	}
	free(root);
}
void Union(node *root1,node *root2)//把ac自动机2合并到1上
{
	head=tail=0;
	q[tail++]=root1;
	q[tail++]=root2;
	int i,j;
	while(head!=tail)
	{
		node *r1=q[head++];
		node *r2=q[head++];
		for(i=0;i<2;i++)
		{
			if(r2->next[i]!=NULL)
			{
				if(r1->next[i]==NULL)
				{
					r1->next[i]=new node();
				}
				r1->next[i]->vis|=r2->next[i]->vis;
				q[tail++]=r1->next[i];
				q[tail++]=r2->next[i];
			}
		}
	}
}
void shilf(char *str,__int64 num)//字符串左移num
{
	int len=strlen(str);
	num%=len;
	num=len-num;
	if(!num)
		return;
	int i=0;
	for(i=0;i<num;i++)
	{
		s1[i]=str[len-num+i];
	}
	for(i=num;i<len;i++)
	{
		s1[i]=str[i-num];
	}
	for(i=0;i<len;i++)
	{
		str[i]=s1[i];
	}
	str[len]=0;
}
int main()
{
	int t,c=0;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		root1=new node();
		root2=new node();
		scanf("%d",&n);
		printf("Case #%d:\n",++c);
		int i;
		__int64 num=0;
		node_num=0;
		build_ac(root1);
		for(i=0;i<n;i++)
		{
			scanf("%s",str);
			if(str[0]=='+')
			{
				shilf(str+1,num);
				if(seach(str+1,root1)||seach(str+1,root2))
					continue;
				insert(str+1,root2);
				build_ac(root2);
				if(node_num>2500)
				{
					Union(root1,root2);
					del(root2);
					root2=new node();
					build_ac(root1);
					build_ac(root2);
					node_num=0;
				}
			}
			else
			{
				shilf(str+1,num);
			//	printf("%s\n",str+1);
				__int64 ans=query(str+1,root1)+query(str+1,root2);
				num=ans;
				printf("%I64d\n",ans);
			}
		}
		del(root1);
		del(root2);
	}
}

ac代码(离线ac自动机就)

#include<stdio.h>
#include<string.h>
char str[5000010],s1[5000010];
int head,tail;
struct node
{
    node *fail;
    node *next[2];
    __int64 cnt;
    node()
    {
        fail=NULL;
        cnt=0;
        for(int i=0;i<2;i++)
            next[i]=NULL;
    }
}*q[8000800];
node *root;
void insert(char *s)
{
    int temp,len,i;
    node *p=root;
    len=strlen(s);
    for(i=0;i<len;i++)
    {
        temp=s[i]-'0';
        if(p->next[temp]==NULL)
            p->next[temp]=new node();
        p=p->next[temp];
    }
    p->cnt++;
}
void build_ac()
{
	head=tail=0;
    q[tail++]=root;
    while(head!=tail)
    {
        node *p=q[head++];
        node *temp=NULL;
        for(int i=0;i<2;i++)
        {
            if(p->next[i]!=NULL)
            {
                if(p==root)
                    p->next[i]->fail=root;
                else
                {
                    temp=p->fail;
                    while(temp!=NULL)
                    {
                        if(temp->next[i]!=NULL)
                        {
                            p->next[i]->fail=temp->next[i];
                            break;
                        }
                        temp=temp->fail;
                    }
                    if(temp==NULL)
                    {
                        p->next[i]->fail=root;
                    }
                }
                q[tail++]=p->next[i];
            }
        }
    }
}
__int64 query(char *str)
{
    __int64 ans=0;
    int len=strlen(str);
    node *p=root,*temp;
    for(int i=0;i<len;i++)
    {
        int x=str[i]-'0';
        while(p->next[x]==NULL&&p!=root)
            p=p->fail;
        p=p->next[x];
        if(p==NULL)
        {
            p=root;
        }
        temp=p;
        while(temp!=root)//没有&&temp->cnt
        {
			ans+=temp->cnt;
			//temp->cnt=-1;
		//	temp->cnt=0;
            temp=temp->fail;
        }
    }
    return ans;
}
void shift(char *str,__int64 num)
{
    int len=strlen(str);
    num%=len;
    num=len-num;
    if(!num)
        return;
    int i=0;
    for(i=0;i<num;i++)
    {
        s1[i]=str[len-num+i];
    }
    for(i=num;i<len;i++)
    {
        s1[i]=str[i-num];
    }
    for(i=0;i<len;i++)
    {
        str[i]=s1[i];
    }
}
int seach(char *s)
{
	int len=strlen(s),i,j,now;
	node *cur=root;
	for(i=0;i<len;i++)
	{
		now=s[i]-'0';
		if(cur->next[now]!=NULL)
		{
			cur=cur->next[now];
		}
		else
			return 0;
	}
	if(cur->cnt)
		return 1;
	return 0;
}
int main()
{
    int t,c=0;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        root=new node();
        scanf("%d",&n);
		printf("Case #%d:\n",++c);
        int i;
        __int64 num=0;
        for(i=0;i<n;i++)
        {
            scanf("%s",str);
            if(str[0]=='+')
            {
				shift(str+1,num);
				if(seach(str+1))
					continue;
                insert(str+1);
            }
            else
            {
                shift(str+1,num);
                build_ac();
                __int64 ans=query(str+1);
                num=ans;
                printf("%I64d\n",ans);
            }
        }
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-07 09:18:27

HDOJ 题目4787 GRE Words Revenge(在线ac自动机,离线也可做)的相关文章

hdu 4787 GRE Words Revenge 在线AC自动机

hdu 4787 GRE Words Revenge Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others)Total Submission(s): 2505    Accepted Submission(s): 614 Problem Description Now Coach Pang is preparing for the Graduate Record Examina

hdu_4787_GRE Words Revenge(在线AC自动机)

题目链接:hdu_4787_GRE Words Revenge 题意: 总共有n个操作,2种操作.每行读入一个字符串. 1.如果字符串以+开头,此为单词(即模式串,不考虑重复) 2.如果字符串以?开头,此为文章(即文本串,查询在此之前的单词在文本串中出现的次数) 题解: 强制在线的AC自动机 贴个大牛的详细题解http://blog.csdn.net/no__stop/article/details/16823479 这样的带合并操作的AC自动机用第二种建树的方式比较方便 1 #include<

HDU4787 GRE Words Revenge(AC自动机 分块 合并)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4787 Description Now Coach Pang is preparing for the Graduate Record Examinations as George did in 2011. At each day, Coach Pang can: "+w": learn a word w "?p": read a paragraph p, an

HDU3341 Lost&#39;s revenge(AC自动机+DP)

题目是给一个DNA重新排列使其包含最多的数论基因. 考虑到内存大概就只能这么表示状态: dp[i][A][C][G][T],表示包含各碱基个数为ACGT且当前后缀状态为自动机第i的结点的字符串最多的数论基因数 其中ACGT可以hash成一个整数(a*C*G*T+c*G*T+g*T+T),这样用二维数组就行了,而第二维最多也就11*11*11*11个. 接下来转移依然是我为人人型,我是丢进一个队列,用队列来更新状态的值. 这题果然挺卡常数的,只好手写队列,最后4500msAC,还是差点超时,代码也

【HDU3341】 Lost&#39;s revenge (AC自动机+状压DP)

Lost's revenge Time Limit: 5000MS Memory Limit: 65535KB 64bit IO Format: %I64d & %I64u Description Lost and AekdyCoin are friends. They always play "number game"(A boring game based on number theory) together. We all know that AekdyCoin is t

HDU 3341 Lost&#39;s revenge(AC自动机+状压DP)

Lost's revenge Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 4548    Accepted Submission(s): 1274 Problem Description Lost and AekdyCoin are friends. They always play "number game"(A bor

[HDU 4787] GRE Words Revenge (AC自动机)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4787 题目大意: 给你若干个单词,查询一篇文章里出现的单词数.. 就是被我水过去的...暴力重建AC自动机- -然后暴力查找.. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 #include <map> 6 #include

●HDU 4787 GRE Words Revenge

题链: http://acm.hdu.edu.cn/showproblem.php?pid=4787 题解: AC自动机(强制在线构造) 题目大意: 有两种操作, 一种为:+S,表示增加模式串S, 另一种为:?S,表示查询S中有多少子串为已经给出的模式串. (同时由于输入根据上一次的答案加密 ,所以强制在线) (事先提一下,对于多次给出的相同模式串,是要去重的,至于怎么去重,就随便用trie树或者map+string就好了.) 进入正题: 难道真的要让AC自动机变得在线起来么? 其实还是用普通A

ZOJ 题目3228 Searching the String(AC自动机)

Searching the String Time Limit: 7 Seconds      Memory Limit: 129872 KB Little jay really hates to deal with string. But moondy likes it very much, and she's so mischievous that she often gives jay some dull problems related to string. And one day, m