hdu 5164 Matching on Array (用map实现的ac自动机)

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5164

题意:

给出长度为n一个母串,给出m个长度为ki子串,匹配的条件是比率相同,如子串4 8 能和 1 2 4匹配。问所有子串在母串中出现多少次。

限制:

1 <= n,m <= 1e5

1 <= ki <= 300000

思路:

赤裸裸的ac自动机啊,不过next数组用map来实现,出题人脑洞真大。

这里有一点还要注意,hdu的g++,结构体里面不能开太大的东西,要不然他ce了还不告诉你,所以把ac自动机结构体里面的东西全搬到外面就可以了。

C++ Code


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119


/*hdu 5164 Matching on Array

题意:

给出长度为n一个母串,给出m个长度为ki子串,匹配的条件是比率相同,如子串4 8 能和 1 2 4匹配。问所有子串在母串中出现多少次。

限制:

1 <= n,m <= 1e5

1 <= ki <= 300000

思路:

赤裸裸的ac自动机啊,不过next数组用map来实现,出题人脑洞真大。

这里有一点还要注意,hdu的g++,结构体里面不能开太大的东西,要不然他ce了还不告诉你,所以把ac自动机结构体里面的东西全搬到外面就可以了。

*/

#include<iostream>

#include<cstdio>

#include<map>

#include<algorithm>

using namespace std;

#define LL __int64

const int N=1000005;

LL ans;

int s[N],p[3*N];

int n,m,q;

map<int,int> next[N];

map<int,int> :: iterator it;

int que[N],head,tail;

int cnt,root,null;

int fail[N],end[N];

struct acm{

int newNode(){

next[cnt].clear();

end[cnt]=0;

return cnt++;

}

void init(){

cnt=0;

null=cnt++;

root=newNode();

}

void insert(int n){

int now=root;

for(int i=0;i<n-1;++i){

int d=__gcd(p[i],p[i+1]);

int t=p[i]/d*10001+p[i+1]/d;

int nxt=next[now][t];

if(nxt==0) nxt=next[now][t]=newNode();

now=nxt;

}

++end[now];

}

void build(){

head=tail=0;

fail[root]=null;

for(it=next[root].begin();it!=next[root].end();++it){

fail[it->second]=root;

que[tail++]=it->second;

}

while(head!=tail){

int now=que[head++];

end[now]+=end[fail[now]];   //

for(it=next[now].begin();it!=next[now].end();++it){

int tmp=fail[now];

int nxt=next[tmp][it->first];

while(tmp!=null && !nxt){ tmp=fail[tmp]; nxt=next[tmp][it->first]; }

if(tmp!=null) fail[it->second]=nxt;

else fail[it->second]=root;

que[tail++]=it->second;

}

}

}

void debug(){

for(int i=0;i<=cnt;i++){

printf("id=%3d,fail=%3d,sum=%3d\n",i,fail[i],end[i]);

for(it=next[i].begin();it!=next[i].end();++it)

printf("(%d,%d) ",it->first,it->second);

puts("");

}

}

void query(int n){

int now=root;

for(int i=0;i<n-1;++i){

int d=__gcd(s[i],s[i+1]);

int t=s[i]/d*10001+s[i+1]/d;

int nxt=next[now][t];

while(now!=null && !nxt){ now=fail[now]; nxt=next[now][t]; }

if(now!=null) now=nxt;

else now=root;

//for(int j=now;j;j=fail[j]){

//  ans+=end[j];

//}

ans+=end[now];

}

}

}acm;

int main(){

int T;

scanf("%d",&T);

while(T--){

ans=0;

acm.init();

scanf("%d%d",&n,&q);

for(int i=0;i<n;++i)

scanf("%d",&s[i]);

while(q--){

scanf("%d",&m);

for(int i=0;i<m;++i)

scanf("%d",&p[i]);

if(m>1) acm.insert(m);

else ans+=n;

}

acm.build();

//acm.debug();

acm.query(n);

printf("%I64d\n",ans);

}

return 0;

}

时间: 2024-10-03 13:20:51

hdu 5164 Matching on Array (用map实现的ac自动机)的相关文章

HDU - 4511 小明系列故事――女友的考验(AC自动机+DP)

Description 终于放寒假了,小明要和女朋友一起去看电影.这天,女朋友想给小明一个考验,在小明正准备出发的时候,女朋友告诉他,她在电影院等他,小明过来的路线必须满足给定的规则: 1.假设小明在的位置是1号点,女朋友在的位置是n号点,则他们之间有n-2个点可以走,小明每次走的时候只能走到比当前所在点编号大的位置: 2.小明来的时候不能按一定的顺序经过某些地方.比如,如果女朋友告诉小明不能经过1 -> 2 -> 3,那么就要求小明来的时候走过的路径不能包含有1 -> 2 ->

HDU 5164Matching on Array(AC自动机)

这是BC上的一道题,当时比赛没有做,回头看看题解,说是AC自动机,想着没有写过AC自动机,于是便试着抄抄白书的模板,硬是搞了我数个小时2000ms时限1800过了= = ! 这里就直接贴上BC的结题报告(#27):http://bestcoder.hdu.edu.cn/solutions.php 1003 Matching on Array 首先我们考虑m=1的情况.给定两个数组A={a1,a2,…,an}和B={b1,b2,…,bk},问B在A中出现了几次.令ci=ai+1ai,1≤i<n,同

hdu 5280 Senior&#39;s Array

题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5280 Senior's Array Description One day, Xuejiejie gets an array $A$. Among all non-empty intervals of $A$, she wants to find the most beautiful one. She defines the beauty as the sum of the interval. Th

HDU 5280 Senior&#39;s Array 最大区间和

题意:给定n个数,要求必须将其中某个数改为P,求改动后最大的区间和可以为多少. 水题.枚举每个区间,如果该区间不修改(即修改该区间以外的数),则就为该区间和,若该区间要修改,因为必须修改,所以肯定是把最小的数修改为P能保证该区间最后和最大,所以比较两种方案的较大者.对于每个区间取出的较大者,再取总共的最大者即可.注意一个trick,枚举到整个区间的时候,是必须要修改一个数的,所以这个最大的这个区间只有一种方案.先预处理1~i的区间和,维护每个区间的最小值和区间和. #include <iostr

003-Tuple、Array、Map与文件操作入门实战

003-Tuple.Array.Map与文件操作入门实战 Tuple 各个元素可以类型不同 注意索引的方式 下标从1开始 灵活 Array 注意for循环的until用法 数组的索引方式 上面的for是下标索引(繁琐用的不多) 下面的for是增强for循环的元素遍历索引(推荐) Map 注意左边是Key,右边是Value _(下划线也可以作为占位符,形成结构,但无名称不可以访问) 文件操作 进行了Source包的引入 .fromFile() getLines 使用了Iterator 欢迎广大爱好

hdu 4941 Magical Forest(STL map &amp; 结构体运用)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4941 Magical Forest Time Limit: 24000/12000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 220    Accepted Submission(s): 105 Problem Description There is a forest c

hdu 5280 Senior&#39;s Array(最大子段和)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5280 题意:将一个长度为n的数组,将里面某一个数改为p,使改变后最大子段和最大. 题解:dp[i]=max(dp[i-1)+a[i],a[i]),表示以第 i 个数结束的最大子段和,时间复杂度为O(n). 1)由于n<=1000,可以暴力解决,将每一个数都依次改为p,求出最大的子段和,再去这些最大子段和中最大的,时间复杂度为O(n*n); #include <iostream> #inclu

HDU 5280 Senior&#39;s Array (暴力,水)

题意:给一个数列,再给一个数字p,要求p一定要替换掉数列中的一个元素,然后求最大连续子序列之和. 思路:1000*1000的复杂度,O(n*n) .就是每个都试,然后求和. 1 #include <bits/stdc++.h> 2 #define LL long long 3 #define pii pair<int,int> 4 #define INF 0x7f7f7f7f 5 using namespace std; 6 const int N=2000; 7 int a[N]

[最大子序列和]Hdu 5280 Senior&#39;s Array

题意:一个序列,在其中一个数必须替换成给定数字p的条件下,求最大连续子序列之和. 依次把每一个数替换成p,求每次的最大连续和,找出最大值.O(n^2). #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> typedef long long ll; using namespace std; const int MAXN=1000+5; const int