博客
关于我
bzoj3439: Kpm的MC密码(四种做法)
阅读量:302 次
发布时间:2019-03-03

本文共 1640 字,大约阅读时间需要 5 分钟。

感想

一开始看错题了。。

然后这题呢,不小心又弄了四个方法,然而我的方法还是最挫的QAQ
挑你们自己喜欢的吧

题解

注意,下文全部的字典树都是倒着建的

1可持久化tri 我的O(nlogn)

你就建一个可持久化tri,然后你就二分一下答案,在1~i这颗字典树上走到这个字符串对应的节点。。

然后看一下出现过多少次就好了,挺简单的

#include
#include
#include
#include
using namespace std;const int N=300005*2;struct qq{ int son[26]; int c;//在多少个串中出现过 }s[N];int num=0;int L[N],R[N],cnt;char s1[N];int n;char ss[N];int root[N];//前i个串void Ins (int &rt1,int x,int rt2){ if (x==-1) return ; if (rt1==0) rt1=++num; s[rt1].c=s[rt2].c+1; int c=ss[x]-'a'; Ins(s[rt1].son[c],x-1,s[rt2].son[c]); for (int u=0;u<26;u++) if (u!=c) s[rt1].son[u]=s[rt2].son[u];}int k;int check (int now,int x)//前多少个字符串 第几个字符串去匹配{ now=root[now]; for (int u=R[x];u>=L[x];u--) { int c=s1[u]-'a'; now=s[now].son[c]; } return s[now].c;}int main(){ s[0].c=0; scanf("%d",&n); for (int u=1;u<=n;u++) { scanf("%s",ss+1);int len=strlen(ss+1); Ins(root[u],len,root[u-1]); L[u]=cnt+1; for (int i=1;i<=len;i++) s1[++cnt]=ss[i]; R[u]=cnt; } for (int u=1;u<=n;u++) { scanf("%d",&k); int ans=-1; int l=1,r=n; while (l<=r) { int mid=(l+r)>>1; if (check(mid,u)>=k) {ans=mid;r=mid-1;} else l=mid+1; } printf("%d\n",ans); } return 0;}

2 乱七八糟的方法O(nlogn)【但是不可以有重复的串】

我们可以吧串从小到大插入,可以知道一个串的Kpm串肯定是在他后面的

于是在后面插的时候如果这个节点之前是别人的终点,你就在别人那里加上自己
最后每个点都可以获得一个集合,拍个序就好了

3 比较优的做法O(n)

大概就是把2的方法,按时间顺序插入,然后我们将他路过的点都加上他自己的信息。。

然后以后某个串的终点的kmp串就是他的终点节点所拥有的信息

4网上烂大街的做法O(nlogn)

就是dfs序+主席树,我也没有认真看,不写了

转载地址:http://tbcq.baihongyu.com/

你可能感兴趣的文章
第七章PL/SQL语言开发
查看>>
Oracle 隐式游标I
查看>>
转---原码,反码,补码的深入理解与原理。
查看>>
浅谈C++ 标准库中的异常 —— stdexcept类
查看>>
【浅谈】main函数的三个参数
查看>>
函数指针
查看>>
C++ initializer_list 类型详解
查看>>
C++中的const成员函数(函数声明后加const,或称常量成员函数)用法详解
查看>>
找不到 快速启动 ,怎么办
查看>>
Ubuntu安装软件以及查看已安装软件的几种方式
查看>>
关于fdisk -l看到的heads
查看>>
ubuntu18.04利用fdisk找到磁盘空闲区,新建分区,挂载
查看>>
C++ vector容器删除操作
查看>>
花书读书笔记(十八)-近似推断
查看>>
花书读书笔记(十九)-深度生成模型
查看>>
《百面机器学习》读书笔记(一)-特征工程
查看>>
《凸优化》中科大-讲解 -系列笔记(汇总55/55)
查看>>
STL教程:C++ STL快速入门(非常详细)
查看>>
MySQL中索引与视图的用法与区别详解
查看>>
【论文泛读03】卷积LSTM网络:一种短时降雨量预测的机器学习方法
查看>>