非常强又非常关心学弟学妹学习的企鹅学长变态的考纲下,我们无奈中选择一起学习新姿势
first:KMP算法
这是一个小迪更过博客的算法,我就不好意思在这里献丑了,所以献上友链一份:http://rabbithu.xyz/index.php?title=2017-04-01-01

second:Trie树(字典树)
嘤嘤嘤,这就是我在oi小组讲的第一堂课了!?(虽然当天大家都很颓,但是算法的简单是毋庸置疑的!)
在有关字符串的问题中,我们会遇到一些子串啊~前缀啊~的问题,如果正常枚举遍历的话复杂度为O(n*m)(n、m为字串长度),obviously,这很慢!那怎么办呢?
这时候,就有一个十分聪明的人,想到了树!可是树和字符串有啥关系?看图就知道了!

上图这棵树中,边代表字母,结点存储是否是一个单词的结尾,这样我们是不是就可以通过一个26叉树存储任何想要的单词了w!
【如此可知,根节点代表一个空串】

此刻肯定已经有一些人在想怎样代码实现了,链前?显然,如果用链前存储的话,我们无论是插入还是查询都需要在每一层遍历当前字母,这样复杂度岂不是爆炸?所以我们就用一个简单机智的方法实现存儿子的过程!

struct node
{
int data;
int childs[26];
}tree[N];

Trie 的节点可以使用一个结构体进行存储,如下代码中,trans[i]表示这个节点边上字符为i 的转移边所到达的儿子节点编号,若为 0 则表示没有这个儿子。是不是特别喵啊!

插入:若对于一个字符串集合为小写的树中插入一个字符串s

事实上我们只要用O(len)的复杂度,一次存入字母边(检查如果有这条边存在,那么直接下一个,否则建边即可),并且在最后标记是单词的结尾就好了!
void insert()
{
int l=strlen(num),now=1;
for (int i=0;i<l;i++)
{
if (!tree[now].childs[num[i]-'a'])
tree[now].childs[num[i]-'0']=tot++;
now=tree[now].childs[num[i]-'a'];
}
tree[now].end=1;
return ;
}

查询:查询一个字符串 S 是否是给定字符串集合中某个串的前缀: 这有什么好说的?不和插入是一样的吗!如果没有这条边直接return false就好啊【不附代码了,哼唧!】 最后送上一道例题:POJ 3630 //其中用到了插入、查询同时进行的复杂度优化,简单易懂

#include<cstdio>
#include<cstring>
#define M 11
using namespace std;
const int N=1e5+5;
int n,t,tot,ans;
char num[M];
struct hhh
{
bool end;
int childs[M];
void clear()
{
memset(childs,0,sizeof(childs));
end=false;
}
}tree[N]; bool insert()
{
int l=strlen(num),now=1;
for (int i=0;i<l;i++)
{
if (!tree[now].childs[num[i]-'0'])
{
tree[now].childs[num[i]-'0']=tot++;
tree[tot-1].clear();
}
else if (i==l-1) return 0;
now=tree[now].childs[num[i]-'0'];
if (tree[now].end) return 0;
}
tree[now].end=1;
return 1;
} int main()
{
scanf("%d",&t);
while (t--)
{
tot=1;
ans=1;
tree[tot++].clear();
scanf("%d",&n);
while (n--)
{
scanf("%s",num);
if (!insert()) ans=0;
}
if (ans)
printf("YES\n");
else printf("NO\n");
}
return 0;
}

如果有小伙伴看到这里,那你可以去尝试一下poj2001 如果没算错的话,只能用指针来实现Trie树 代码如下:

#include<cstdio>
#include<cstring>
#define N 1111
#define M 22
using namespace std;
int n,i;
char ha[N][M];
struct node
{
int count;
node *childs[26];
node()
{
count=0;
int i;
for(i=0;i<26;i++)
childs[i]=NULL;
}
};
node *root = new node;
node *now,*newnode; void insert(int x)
{
int l=strlen(ha[x]);
now=root;
for (int j=0;j<l;j++)
{
if (now->childs[ha[x][j]-'a'])
{
now=now->childs[ha[x][j]-'a'];
++(now->count);
}
else
{
newnode=new node;
++(newnode->count);
now->childs[ha[x][j]-'a']=newnode;
now=newnode;
}
}
return ;
} void search(int x)
{
now=root;
int l=strlen(ha[x]),cnt=0;
char ans[M];
for (int j=0;j<l;j++)
{
now=now->childs[ha[x][j]-'a'];
ans[cnt++]=ha[x][j];
ans[cnt]='\0';
if (now->count==1)
{
printf("%s %s\n",ha[x],ans);
return ;
}
}
printf("%s %s\n",ha[x],ans);
return ;
} int main()
{
while (~scanf("%s",ha[i])) insert(i++);
for (int j=0;j<i;j++) search(j);
return 0;
}

我觉得不会有人看到这里了…… 以下是20160603模拟easy round1 T2 震惊

Description “震惊,OIer熬夜学习可持久化tire树竟是因为……” ——企鹅头条 钫企鹅听说哦艾尔要加入企鹅头条,书写传奇新闻,夺得普利鹅2333年新闻奖。便让他去震惊部去历练一下。 震惊有一些不同的写法,均由小写字母构成,且长度不超过 100100 。比如 : shock,choc,schock 等。每一种震惊的写法,在震惊部拥有不同的权值。 给定 nn 种震惊写法初始的权值,并进行 mm 个操作。 操作分两种 : 1.修改 : 给出一种震惊的写法,若这种写法存在 , 则将这种震惊写法的权值修改为 xx 。 2.询问 : 在 xx 次操作前,某种震惊写法的权值。即若当前为第 dd 次操作 , 则询问第 d−xd−x 次操作后 , 该种震惊写法的权值 。 注意:本题采用强制在线 , 请注意输入输出格式 Input 第一行两个整数 nn , mm 。 接下来 nn 行每行一个字符串 SS ,和一个整数 xx , 分别代表一种震惊的写法和该种写法的初始权值 。 接下来 mm 行每行一个字符串 SS 和一个整数 xx 。字符串 SS 代表一种震惊的写法。 如果本次操作是修改, xx 代表将这种震惊的写法的权值修改为 xx 。 如果本次操作是询问, xx 代表询问 xx 次操作前,这种震惊写法的权值 。 本题采用强制在线,若上次操作的输出为 Er 或 Shock ,则代表本次操作为询问,否则代表本次操作为修改。规定第 11 次操作为修改 。 Output 输出共 mm 行。每行对应一次操作。 对于每组修改,如果修改成功(即存在对应的震惊写法),输出 Ac 。如果不存在对应的震惊写法,输出 Er 。 对于每组询问,如果存在对应的震惊写法,输出对应 xx 次操作前,某种震惊写法的权值 xx 。如果不存在对应的震惊写法,输出 Shock 。

题解:暂割

AC代码:

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define M 1111
#define N 11111
#define inf 1111111
using namespace std;
int n,m,x,b,pre,j;
char a[M];
struct ha
{
int time,dt;
bool operator < (ha j) const
{
return time<j.time;
}
ha()
{
time=inf;
dt=0;
}
};
struct hhh
{
vector <ha> data;
bool jy;
hhh *childs[30];
hhh()
{
for(int i=0; i<26; i++)
childs[i]=NULL;
jy=0;
}
};
hhh *root=new hhh;
hhh *now,*newnode; void insert(int y)
{
int l=strlen(a);
now=root;
for (int i=0; i<l; i++)
{
if (now->childs[a[i]-'a'])
now=now->childs[a[i]-'a'];
else
{
newnode=new hhh;
now->childs[a[i]-'a']=newnode;
now=newnode;
}
}
ha u;
u.time=0;
u.dt=y;
now->data.push_back(u);
now->jy=1;
return ;
} void query(int y)
{
now=root;
int l=strlen(a);
for (int i=0; i<l; i++)
{
if (now->childs[a[i]-'a'])
now=now->childs[a[i]-'a'];
else
{
printf("Shock\n");
pre=0;
return ;
}
}
if (!(now->jy))
{
printf("Shock\n");
pre=0;
return ;
}
if (j-y>=0)
{
vector <ha> :: iterator it;
ha uu;
uu.time=j-y;
it=upper_bound(now->data.begin(),now->data.end(),uu);
it--;
printf("%d\n",it -> dt);
}
else
{
int v=now->data.size()-1;
printf("%d\n",now->data[v].dt);
}
pre=1;
return ;
} void change(int y)
{
int l=strlen(a);
now=root;
for (int i=0; i<l; i++)
{
if (now->childs[a[i]-'a'])
{
now=now->childs[a[i]-'a'];
}
else
{
printf("Er\n");
pre=0;
return ;
}
}
if (!(now->jy))
{
printf("Er\n");
pre=0;
return ;
}
printf("Ac\n");
pre=1;
ha u;
u.time=j;
u.dt=y;
now->data.push_back(u);
return ;
} int main()
{
freopen("2(2).in","r",stdin);
freopen("2.out","w",stdout);
scanf("%d%d",&n,&m);
pre=1;
while(n--)
{
scanf("%s %d",a,&b);
insert(b);
}
for (j=1; j<=m; j++)
{
scanf("%s %d",a,&x);
if (pre) change(x);
else query(x);
}
return 0;
}

<转自原博客> 可爱的字符串算法们的更多相关文章

  1. 原博客地址http://blog.chinaunix.net/uid/20656672.html弃用

    原博客地址http://blog.chinaunix.net/uid/20656672.html弃用

  2. [原博客] BZOJ 2242 [SDOI2011] 计算器

    题目链接 noip级数论模版题了吧.让求三个东西: 给定y,z,p,计算`Y^Z Mod P` 的值. 给定y,z,p,计算满足`xy≡ Z ( mod P )`的最小非负整数. 给定y,z,p,计算 ...

  3. 原博客地址http://blog.chinaunix.net/uid/20656672.html不再维护(10年前数百篇oracle/teradata性能优化、故障处理案例)

    原博客地址http://blog.chinaunix.net/uid/20656672.html不再维护(数百篇oracle/teradata性能优化.故障处理原创文章) 858871 top 500 ...

  4. 为了确认是您本人在申请搬家,请在原博客发表一 篇标题为《将博客搬至CSDN》的文章,并将文章地址填写在上方的"搬家通知地址"中

    为了确认是您本人在申请搬家,请在原博客发表一 篇标题为<将博客搬至CSDN>的文章,并将文章地址填写在上方的"搬家通知地址"中

  5. [原博客] POJ 1067 取石子游戏

    题目链接有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可以在两堆中同时取走相同数量的石子.最后把石子全部取完者 ...

  6. [原博客] BZOJ 2725 : [Violet 6]故乡的梦

    这个题在bzoj上好像是个权限题,想做的可以去Vani的博客下载测试数据.这里有题面. 简单叙述一下题意:给你一个n个点.m条边的带权无向图,S点和T点,询问Q次删一条给定的边的S-T最短路. 其中  ...

  7. [原博客] POI系列(3)

    正规.严谨.精妙. -POI BZOJ 1131 : [POI2008]Sta 树形dp吧,让求找一个点使以这个点深度和最小.首先可以随便整出来一棵树,对于每个节点记录down[i]以i为根下面的点的 ...

  8. [原博客] POI系列(1)

    正规.严谨.精妙. -POI 发现POI(波兰信息学奥赛)的题都很有意思.于是开刷bzoj上的poi题目(按ac人数降序..).顺手写一写题解,加深印象. 为了防止一篇文章过于长,打算每五道题另起一篇 ...

  9. [原博客] HEOI2014 行记

    HEOI: 河北省信息学竞赛省队选拔赛 HEOI数据标程下载 百度盘 http://pan.baidu.com/s/1qWx7YAo 又到了一年一度的HEOI呢. 我果然还是太弱了呢. Day0 报到 ...

随机推荐

  1. Struts2基础学习2

    Struts2基础学习2 项目结构,测试页面与实体类 <%@ page language="java" contentType="text/html; charse ...

  2. .NET 客户IP地址捕捉

    MVC模式下要获取客户IP可以在ActionFilterAttribute中进行拦截 filterContext.HttpContext.Request.UserHostAddress 同样,在Web ...

  3. Struts2之基于配置的字段校验

    上一篇struts2之输入校验介绍了手动完成输入校验,也即依靠重写validate方法和validateXxx方法,指定请求某个方法时对传入的参数进行校验. 本篇介绍基于配置的字段校验.下面是登录的常 ...

  4. python__高级 : 动态添加 对象属性, 类属性, 对象实例方法, 类静态方法, 类方法

    给对象添加实例属性,可以直接这样  t.age = 18   ( 假设 t = Test() )  给类添加类属性 , 也可以直接这样  Test.age = 18 那给对象添加实例方法,可以在类外面 ...

  5. 数据分析处理库Pandas——数值运算

    求和 对每行或每列求和. 均值 对每行或每列求均值. 最大最小值 对每行或每列求最大值或最小值. 中位数 对每行或每列求中位数. 相关系数和协方差 先导入一个DataFram结构的数据,再对这些数据计 ...

  6. C++基础 匿名对象

    以下几种情况又会匿名对象 (1)对象构造 与 匿名对象 Test t1 = Test(); 这时,Test()会构造匿名对象,并且是调用无参构造函数,然后 t1 将匿名对象扶正. (2)对象赋值 与 ...

  7. 3,版本控制git-多人协作

    如果你想获得一份已经存在了的 Git 仓库的拷贝,比如说,你想为某个开源项目贡献自己的一份力,这时就要用到 `git clone` 命令. 如果你对其它的 VCS 系统(比如说Subversion)很 ...

  8. P2370 yyy2015c01的U盘

    P2370 yyy2015c01的U盘 题目背景 在2020年的某一天,我们的yyy2015c01买了个高端U盘. 题目描述 你找yyy2015c01借到了这个高端的U盘,拷贝一些重要资料,但是你发现 ...

  9. Android 支付宝H5 没有回调

    今天测试反馈问题,说,手机上没有安装支付宝的,调用支付宝支付之后,没有回调.不提示成功也不提示失败. 我自己试了半天也都是没有问题 .后来终于可以试出来了. 发现原来是,清单里面注册的Activity ...

  10. sprintf()函数使用异常

    调试STM32F103,比如如下代码:使用springf函数,这个函数是把最后两个参数先格式化成字符串 ,输出到ERROR_STRING,如果他们合并的长度大于30会出现深情况? ] sprintf( ...