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); } } } }
版权声明:本文为博主原创文章,未经博主允许不得转载。