[HDU4787]GRE Words Revenge 解题报告
这是我之前博客里提到的一道AC自动机的练手题,但是要完成这道题,我之前博客里提到的东西还不够,这里总结一下这道题。
这道题不是一般的裸的AC自动机,它的询问和插入是交叉出现的所以用我之前写的板子不大合适,这道题在构建自动机时不能改变原有的 Trie树 的结构,所以没有代表字符串的结点的不需要去改它的值,所以我在 build() 函数 处做了一些修改。在复杂度方面,如果是强上普通的AC自动机,最差会达到O(n^2),感觉不太好。我们这里可以用到平方分割的套路,搞大小两个自动机,每次插入都在小自动机上进行,当小自动机里的结点达到一定量(sqrt(n))时,就将两自动机合并,并将小自动机清空。合并的方式也很好理解,就将两个自动机的节点一一对应,若小自动机上的结点在大自动机上没有,就在大自动机上新建结点,并修改它的值。总复杂度大概是这样:O(n*sqrt(n)(小的)+O(sqrt(n)*n)(大的)=O(n*sqrt(n))。其实那个上界也不一定要严格的根号n,自己大概估计一个常数就差不多了。哦对,还有一点,我发现好多板子里在构建新结点时都打了一个 newnode() 函数,包括我自己的板子也是这么打的。这样打其实是很慢的,我在做这道题时就各种 T飞 ,后来把这个去掉搞成其他的方法就快了很多(虽然我也不知道为什么),下面的代码里会体现。
祝大家切题愉快
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> #define maxn (511111) #define N (6000000) #define il inline #define ll long long #define RG register using namespace std; char s[N],ss[N]; struct Trie{ int son[maxn][2],fail[maxn],size,root; bool val[maxn]; //标记是否出现 il void init(){ size=1; root=0; memset(son,0,sizeof(son)); memset(val,0,sizeof(val)); memset(fail,0,sizeof(fail)); } il int idx(char c){ //卡常专用 return c-'0'; } il int insert(char *s){ //插入新单词 RG int cur=root; for(RG int i=0;s[i];i++){ //卡常小技巧,不要每次计算len RG int id=idx(s[i]); if( !son[cur][id] ) son[cur][id]=size++; cur=son[cur][id]; } val[cur]=true; return cur; } il bool in(char *s){ //查询单词是否在自动机内 RG int cur=root; for(RG int i=0;s[i];i++){ RG int id=idx(s[i]); if( !son[cur][id] ) return false; cur=son[cur][id]; } return val[cur]; } il void build(){ //构建自动机 queue<int>Q; for(RG int i=0;i<2;i++) if( son[root][i] ) //只加入队列,不用修改值 Q.push(son[root][i]); while(!Q.empty()){ RG int cur=Q.front(); Q.pop(); for(RG int i=0;i<2;i++){ RG int Son=son[cur][i]; if(!Son) continue; Q.push(Son); //同上 RG int f=fail[cur]; while(f && !son[f][i] ) f=fail[f]; fail[Son]=son[f][i]; } } } il int query(char *s){ //查询次数 RG int cur=root,ans=0; for(RG int i=0;s[i];i++){ RG int id=idx(s[i]); while(cur && !son[cur][id] ) cur=fail[cur]; cur=son[cur][id]; RG int k=cur; while(k){ ans+=val[k]; k=fail[k]; } } return ans; } }small,big; il void dfs(RG int u,RG int v){ //用于合并 for(RG int i=0;i<2;i++) if(small.son[v][i]){ RG int cur2=small.son[v][i]; if( !big.son[u][i] ){ memset(big.son[big.size],0,sizeof(big.son[big.size])); big.son[u][i]=big.size++; //建立新结点 } RG int cur1=big.son[u][i]; big.val[cur1] |=small.val[cur2]; dfs(cur1,cur2); } } il void join(){ dfs(0,0); small.init(); big.build(); } int main(){ RG int Case,n; scanf("%d",&Case); for(RG int k=1;k<=Case;k++){ printf("Case #%d:\n",k); scanf("%d",&n); small.init(); big.init(); RG int l=0; while(n--){ scanf("%s",s); RG int len=strlen(s+1); ss[0]=s[0]; for(RG int i=0;i<len;i++) ss[i+1]=s[ (i+l%len+len)%len+1 ]; ss[len+1]='\0'; if(ss[0]=='+'){ if( small.in(ss+1) || big.in(ss+1) ) continue; //若该单词已经存在就跳过 small.insert(ss+1); small.build(); if( small.size>2333 ) join(); } else{ l=small.query(ss+1)+big.query(ss+1); printf("%d\n",l); } } } return 0; }
真是服了这鬼畜的缩进。。。真难看。。。
[HDU4787]GRE Words Revenge 解题报告的更多相关文章
- HDU-4787 GRE Words Revenge 解题报告
这是我之前博客里提到的一道AC自动机的练手题,但是要完成这道题,我之前博客里提到的东西还不够,这里总结一下这道题. 这道题不是一般的裸的AC自动机,它的询问和插入是交叉出现的所以用我之前写的板子不大合 ...
- HDU4787 GRE Words Revenge【AC自动机 分块】
HDU4787 GRE Words Revenge 题意: \(N\)次操作,每次记录一个\(01\)串或者查询一个\(01\)串能匹配多少个记录的串,强制在线 题解: 在线的AC自动机,利用分块来降 ...
- HDU4787 GRE Words Revenge(AC自动机 分块 合并)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4787 Description Now Coach Pang is preparing for ...
- 2011 ACM-ICPC 成都赛区解题报告(转)
2011 ACM-ICPC 成都赛区解题报告 首先对F题出了陈题表示万分抱歉,我们都没注意到在2009哈尔滨赛区曾出过一模一样的题.其他的话,这套题还是非常不错的,除C之外的9道题都有队伍AC,最终冠 ...
- CH Round #56 - 国庆节欢乐赛解题报告
最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树 ...
- 二模13day1解题报告
二模13day1解题报告 T1.发射站(station) N个发射站,每个发射站有高度hi,发射信号强度vi,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...
- BZOJ 1051 最受欢迎的牛 解题报告
题目直接摆在这里! 1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4438 Solved: 2353[S ...
- 习题:codevs 2822 爱在心中 解题报告
这次的解题报告是有关tarjan算法的一道思维量比较大的题目(真的是原创文章,希望管理员不要再把文章移出首页). 这道题蒟蒻以前做过,但是今天由于要复习tarjan算法,于是就看到codevs分类强联 ...
- 习题:codevs 1035 火车停留解题报告
本蒟蒻又来写解题报告了.这次的题目是codevs 1035 火车停留. 题目大意就是给m个火车的到达时间.停留时间和车载货物的价值,车站有n个车道,而火车停留一次车站就会从车载货物价值中获得1%的利润 ...
随机推荐
- SpringCloud 学习(二) :服务注册与发现Eureka
Spring Cloud应用中可以支持多种的服务治理框架,比如Eureka.Consul.Zookeeper等,现在我们用的是consul,本文以SpringCloud Dalston.SR5版本介绍 ...
- JavaScript学习笔记(六)—— 异步编码
第七章 异步编码 1 事件处理程序 处理程序:即网页加载完毕后将执行的代码,称回调函数或监听器: 包含:处理函数+window.onload=函数名; <script language=&qu ...
- 从零开始的Python学习Episode 17——序列化
序列化 我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语 言中也被称之为serialization,marshalling,flattenin ...
- NO.7:自学python之路------类的方法、异常处理、socket网络编程
引言 我visual studio 2017就算体积巨大.启动巨慢.功能简陋也不会安装PyCharm的,嘿呀,真香.好吧,为了实现socket网络编程,更换了软件. 正文 静态方法 只是在名义上归类管 ...
- TensorFlow --- 01初识
由于博客园对Markdown支持不够友好,阅读此文请前往云栖社区:TensorFlow --- 01初识
- tar.gz 文件解压 (安装 netbean 时会用到)
sudo tar xvf jdk-7u45-linux-i586.tar.gz -C /usr/lib 参考文章 http://hi.baidu.com/xiaomeng008/item/5e787b ...
- Python数据分析工具库-Numpy 数组支持库(二)
1 shape变化及转置 >>> a = np.floor(10*np.random.random((3,4))) >>> a array([[ 2., 8., 0 ...
- 微服务注册与发现 —— eureka
基础概念 在微服务系统中,服务的注册和发现是第一步,常用的有: Eureka:https://github.com/Netflix/eureka Zookeeper:https://zookeeper ...
- Alpha 冲刺报告(4/10)
Alpha 冲刺报告(4/10) 队名:洛基小队 峻雄(组长) 已完成:继续行动脚本的编写 明日计划:尽量完成角色的移动 剩余任务:物品背包交互代码 困难:具体编码进展比较缓慢 ----------- ...
- python学习笔记05:贪吃蛇游戏代码
贪吃蛇游戏截图: 首先安装pygame,可以使用pip安装pygame: pip install pygame 运行以下代码即可: #!/usr/bin/env python import pygam ...