KMP Trie 例题讲解

文章目录

    • HDU 4763 Theme Section
      • 题意:
      • 题解:
      • 代码:
    • POJ 3630 Phone List
      • 题意:
      • 题解:
      • 代码:
    • HDU 3746 Cyclic Nacklace
      • 题意:
      • 题解:
      • 代码:
    • HDU 2087 剪花布条
      • 题意:
      • 题解:
      • 代码:
    • HDU 1251 统计难题
      • 题意:
      • 题解:
      • 代码:
    • HDU 2072 单词数
      • 题意:
      • 题解:
      • 代码:
    • POJ 2513 Colored Sticks
      • 题意:
      • 题解:
      • 代码:

HDU 4763 Theme Section

题意:

题解:

代码:

POJ 3630 Phone List

题意:

n个号码,如果有一个号码是其他号码的前缀,则输出NO,否则输出YES

题解:

根据字典序排序,然后判断相邻的两个字典序是否有前缀

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
using namespace std;
char s[30];
string w[100005];
int main()
{int T,n;bool F=0;scanf("%d",&T);while(T--){scanf("%d",&n);F=0;//memset(w,0,sizeof(w));for(int i=0;i<n;i++)cin>>w[i];sort(w,w+n);for(int i=1;i<n;i++){if(w[i].length()>w[i-1].length()){int j;for(j=0;j<w[i-1].size();j++)if(w[i][j]!=w[i-1][j])break;if(j==w[i-1].size())F=1;    }}if(F) cout<<"NO"<<endl;else cout<<"YES"<<endl;}}

静态数组写字典树做法:

#include <cstdlib>
#include <cstdio>
#include <cstring>
typedef struct node //节点的结构体
{bool end;//结束的标志int  a[10];
}node;
node phonelist[100000];
int x;
int flag;
void Init()
{flag=1;//标志x=0; //初始位置;for(int i=0;i<100000;i++){phonelist[i].end=false;for(int j=0;j<10;j++)phonelist[i].a[j]=-1;}
}
int build(char *s) //建立字典树
{int k,now=0,tag=0;// 初始位置int len=strlen(s);for(int i=0;i<len;i++){k=s[i]-'0';if(phonelist[now].a[k]==-1){tag=1;//说明进入一个新的位置phonelist[now].a[k]=++x; //给数组赋值now=x;//下一个位置}else{now=phonelist[now].a[k];if(phonelist[now].end)return 0;  //单词的结束标志}}phonelist[now].end=true; //标记结束的节点if(!tag) return 0;return 1;
}
int main()
{//freopen("1.txt","r",stdin);int n,m;char s[12];scanf("%d",&n);while(n--){Init();scanf("%d",&m);for(int i=0;i<m;i++){scanf("%s",s);if(flag)flag=build(s);}if(flag)printf("YES\n");elseprintf("NO\n");}return 0;
}

HDU 3746 Cyclic Nacklace

题意:

一个字符串,在串后面补全几个字符,可以使他的全部字符最少循环2次以上,求最少补几个字符?

题解:

kmp算法的next数组
next数组的含义为, T[0…i-1]中的最大公共真前缀/后缀, 对于0-indexed求出的next数组实际上为1-M

next[M]为T中的最大公共真前缀/后缀, 这样M-next[M]应该就是循环节的长度len(仔细思考)
如果next[M]为0说明没有循环节, M%len==0说明循环节完全重复包含

首先这里用到一个kmp算法的最长相等前后缀算法next[]
然后很重要的一点:补全后字符串循环体L为strlen(s)-next[n]
这里有三种可能性:
1,字符串里已经有两次以上循环,而且都已补全这种就不用补全了,判断方式: 相等前后缀肯定不为零,且总长n%L==0
2,字符串里已经有两次以上循环,后续循环未补全这种要把单次循环的补全,由于已经有两次以上的循环,那么前后缀肯定要比单次循环要长(懒得证明)那么 前后缀%单次循环 就是循环剩下来的: 比如 ababa 前后缀是aba 单次循环是 ab 剩下来的就是a那么我们要补全的就是 单词循环-剩下来的: b ababa + b = ababab
3, 字符串里没有两次以上循环这种要补全两次由于没有两次以上的循环,那么前后缀肯定要比单次循环要短(同上)那么我们就输出 单词循环-前后缀: l-next[n]这种可以和第二种合并

代码:

#include<cstdio>
#include<cstring> 
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX=1e5+13;
char w[MAX];
int cnt[MAX];
int F;
void JZY(int len )
{F=-1;cnt[0]=-1;for(int i=0;i<len;){if(F==-1||w[i]==w[F]) cnt[++i]=++F;else F=cnt[F];}
}
int main()
{int T;int m;scanf("%d",&T);while(T--){scanf("%s",w);int len=strlen(w);JZY(len);m=len-cnt[len];if((m!=len)&&(len%m==0)) printf("0\n");else printf("%d\n",m-cnt[len]%m);}
}

HDU 2087 剪花布条

题意:

一个目标串,一个模板串,问目标串最多可以剪除几个模板串?

题解:

可以用kmp来做,也可以用hash来做

代码:

hash代码:

#include<iostream>
#include<vector>
#include<algorithm>
#include<string.h>
#include<string>
#include<cstdio>
using namespace std;
#define maxn 1001
string a;
string b;
const int B = 100000007;
typedef unsigned long long ull;
ull _hash(int al, int bl)
{if (al < bl)return 0;ull t = 1, ah = 0, bh = 0, cnt = 0;for (int i = 0; i < bl; i++)t *= B;for (int i = 0; i < bl; i++)ah = ah*B + a[i];for (int i = 0; i < bl; i++)bh = bh*B + b[i];for (int i = 0; i + bl<=al; i++){//cout << a << "\n" << b << endl;//cout << ah << "\t" << bh << endl;if (ah == bh){cnt++;ah = ah - a[i + bl - 1] + '$';//这是关键一步,更改字母之后hash值发生变化,所以变化量为'$'-a[i+bl-1]a[i + bl-1] = '$';//更改已匹配的最后一个字母}if (i+bl<al)ah = ah*B - a[i] * t + a[i + bl];}return cnt;
}
int main()
{while (cin>>a&&a!="#"){   cin >> b;int al = a.length();int bl = b.length();ull res = _hash(al, bl);cout << res << endl;}
}

kmp代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxx=1e6+10;
int Next[maxx];
char s[maxx],p[maxx];
int len1,len2;
void getnext()
{int i=0,j=-1;Next[0]=-1;while(i<len1){if(j==-1||p[i]==p[j]){++i;++j;if(p[i]==p[j])Next[i]=Next[j];elseNext[i]=j;}elsej=Next[j];}
}
void getkmp()
{int num=0,i=0,j=0;while(i<len2){if(j==-1|s[i]==p[j]){++i;++j;}elsej=Next[j];if(j==len1){++num;j=0;}}printf("%d\n",num);
}
int main()
{while(scanf("%s",s),s[0]!='#'){scanf("%s",p);len1=strlen(p);len2=strlen(s);getnext();getkmp();}return 0;
}

HDU 1251 统计难题

题意:

统计出以某个字符串为前缀的单词数量

题解:

模板题,map也可以做

代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int N=1e6+1;
const int mod=1e9+7;
const double pi=acos(-1);
const double eps=1e-8;
char s[12];
int trie[N][26],sum[N],tot,root;
void sert()
{root=0;for(int i=0;s[i]!='\0';i++){int id=s[i]-'a';if(!trie[root][id]) trie[root][id]=++tot;sum[trie[root][id]]++;root=trie[root][id];}
}
int finf()
{root=0;int id;for(int i=0;s[i]!='\0';i++){id=s[i]-'a';if(!trie[root][id]) return 0;root=trie[root][id];}return sum[root];
}
int main()
{while(gets(s)){if(s[0]=='\0') break;sert();}while(gets(s)){printf("%d\n",finf());}
}

HDU 2072 单词数

题意:

统计不同单词的数量

题解:

可以用map来做
不过练习字典树

代码:

#include<iostream>
#include<sstream>
using namespace std;struct node{int flag;struct node *next[26];node(){for(int i=0;i<26;i++){this->next[i]=NULL;}this->flag=0;}
};node *root;
int ans;
void Insert(string str)
{node *p=root;for(int i=0;i<str.size();i++){if(p->next[str[i]-'a']==NULL)p->next[str[i]-'a']=new node();p=p->next[str[i]-'a'];}p->flag++;if(p->flag==1)ans++;
}int main()
{string str,str1;while(getline(cin,str)){root=new node();ans=0;if(str=="#")break;istringstream ss(str);while(ss>>str1){Insert(str1);}cout<<ans<<endl;}return 0;
}
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<set>
#include<set>
#include <sstream>   
using namespace std; 
int main()
{                  string a;    while(getline(cin,a)&& a != "#"){    istringstream stream(a);string w;    set<string> map;    while(stream >>w)   map.insert(w); printf("%d\n",map.size());
}}

POJ 2513 Colored Sticks

题意:

给你一堆木棍。每根棍子的每个端点都用某种颜色着色。有没有可能把棍子在一条直线上对齐,使接触的端点的颜色是相同的颜色?

题解:

欧拉通路+并查集+字典树
判断欧拉通路是否存在的方法

有向图:图连通,有一个顶点出度大入度1,有一个顶点入度大出度1,其余都是出度=入度。

无向图:图连通,只有两个顶点是奇数度,其余都是偶数度的。

代码:

#include <cstdio>
#include <cstring>
int const MAX = 500005;
int fa[MAX], d[MAX], cnt;struct Trie
{int sz, t[MAX][15];int jud[MAX];Trie(){sz = 1;memset(t[0], -1, sizeof(t));jud[0] = 0;}void clear(){sz = 1;memset(t[0], -1, sizeof(t));jud[0] = 0;}int idx(char c){return c - 'a';}void insert(char* s, int v){int u = 0, len = strlen(s);for(int i = 0; i < len; i++){int c = idx(s[i]);if(t[u][c] == -1){memset(t[sz], -1, sizeof(t[sz]));jud[sz] = 0;t[u][c] = sz++;}u = t[u][c];}jud[u] = v;}int search(char* s){int u = 0, len = strlen(s);for(int i = 0; i < len; i++){int c = idx(s[i]);if(t[u][c] == -1) return -1;u = t[u][c];}if(jud[u]) return jud[u];return -1;}
}t;void Init()
{for(int i = 0; i < MAX; i++)fa[i] = i;
}int Find(int x)
{return x == fa[x] ? x : fa[x] = Find(fa[x]);
}void Union(int a, int b)
{int r1 = Find(a);int r2 = Find(b);if(r1 != r2)fa[r1] = r2;
}bool eluer()
{int sum = 0, t = -1;for(int i = 1; i < cnt; i++)if(d[i] % 2) sum++;if(sum != 0 && sum != 2)return false;for(int i = 1; i < cnt; i++){if(t == -1)t = Find(i);else if(Find(i) != Find(t)) return false;}return true;
}int main()
{char s1[20],s2[20];cnt = 1;Init();t.clear();while(scanf("%s %s", s1, s2) != EOF){if(t.search(s1) == -1)t.insert(s1, cnt++);int u = t.search(s1);if(t.search(s2) == -1)t.insert(s2, cnt++);int v = t.search(s2);Union(u, v);d[u]++;d[v]++;}if(eluer())printf("Possible\n");elseprintf("Impossible\n");
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/319051.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P4640-[BJWC2008]王之财宝【OGF,Lucas定理】

正题 题目链接:https://www.luogu.com.cn/problem/P4640 题目大意 nnn种物品&#xff0c;其中ttt种物品是有个数限制的&#xff0c;第iii种限制为bib_ibi​&#xff0c;求选出mmm个物品的方案数%p\% p%p的值 1≤n,m,bi≤109,0≤t≤15,p∈[1,105]∩Pri1\leq n,m,b_i\leq 10^9,0…

[机器翻译]参与 Microsoft 开放源代码软件项目的方式

下面是一个事实&#xff1a;Microsoft 托管在 GitHub&#xff0c;包括.NET 编译器平台&#xff0c;也称为"Roslyn"具有多达 4 万行代码等一些相当大的大约 2,000 开放源代码软件 (OSS) 存储库。很多开发人员的代码将更改提交到数以百万计的计算机运行的项目可能会令人…

codeforces1485 F. Copy or Prefix Sum(dp)

F. Copy or Prefix Sum Venice technique简要就是懒标记思想。 由于前缀和数组和原数组一一对应&#xff0c;这里我们选择求aia_iai​的前缀和数组的方案数&#xff08;下面aia_iai​表示原题数组的前缀和&#xff09; 不难得知原题目的两个条件即 biai−ai−1→aibiai−1b_ia…

【蓝桥杯】 2018年国赛 矩阵求和

题目 题目&#xff1a; 经过重重笔试面试的考验&#xff0c;小明成功进入 Macrohard 公司工作。 今天小明的任务是填满这么一张表&#xff1a; 表有 n 行 n 列&#xff0c;行和列的编号都从1算起。 其中第 i 行第 j 个元素的值是 gcd(i, j)的平方&#xff0c; gcd 表示最大公…

F - GCD or MIN(数论)

F - GCD or MIN 首先gcd⁡(x,y)≤min⁡(x,y)\gcd(x,y)\leq \min(x,y)gcd(x,y)≤min(x,y) 数组中任意2个数的gcd可能是一种方案&#xff0c;任意3个数的gcd可能是一种方案… 如果我们能够把原数组任意个数的gcd全部列出来&#xff0c;能够满足题意的数一定在这些数之中&#…

P4199-万径人踪灭【FFT】

正题 题目链接:https://www.luogu.com.cn/problem/P4199 题目大意 给出一个只包含a,ba,ba,b的字符串 求有多少个不连续的回文子序列&#xff08;字母回文&#xff0c;位置对称&#xff09; 1≤n≤1051\leq n\leq 10^51≤n≤105 解题思路 这个不连续一看就很nt&#xff0c;考…

被低估的.net(上) - 微软MonkeyFest 2018广州分享会活动回顾

前天, 2018年11月10日, 广州图书馆\微软云开发者社区\广东职业教育信息化研究会\珠三角技术沙龙在广州图书馆负一层1号报告厅搞了一场”微软最有价值专家(MVP)广州分享会 - MonkeyFest 2018广州分享会”. 这是在广州图书馆官方微信公众号上的活动报名链接: https://mp.weixin.q…

[蓝桥杯][2017年第八届真题]发现环

题目链接 题目描述 小明的实验室有N台电脑&#xff0c;编号1~N。原本这N台电脑之间有N-1条数据链接相连&#xff0c;恰好构成一个树形网络。在树形网络上&#xff0c;任意两台电脑之间有唯一的路径相连。 不过在最近一次维护网络时&#xff0c;管理员误操作使得某两台电脑之间增…

P7323-[WC2021]括号路径【并查集,启发式合并】

正题 题目链接:https://www.luogu.com.cn/problem/P7323 题目大意 给出nnn个点的一张有向图。每个边(u,v,w)(u,v,w)(u,v,w)表示u−>vu->vu−>v有一个类型www的左括号边&#xff0c;v−>uv->uv−>u有一个类型www的右括号边。 求图中有多少点对满足它们之间…

P3565 [POI2014]HOT-Hotels(树形dp+长链剖分)

P3565 [POI2014]HOT-Hotels 参考题解 题目大意&#xff1a; 给定一棵树&#xff0c;在树上选 3 个点&#xff0c;要求两两距离相等&#xff0c;求方案数。 三个点树上两两距离为d存在下面两种情况 某个点三个子树&#xff08;保证该点是LCA&#xff09;中分别由三个点距离它为…

C#的RSA加密解密签名,就为了支持PEM PKCS#8格式密钥对的导入导出

差点造了一整个轮子.Net Framework 4.5 里面的RSA功能&#xff0c;并未提供简单对PEM密钥格式的支持&#xff08;.Net Core有咩&#xff1f;&#xff09;&#xff0c;差点&#xff08;还远着&#xff09;造了一整个轮子&#xff0c;就为了支持PEM PKCS#8、PKCS#1格式密钥对的导…

P4494-[HAOI2018]反色游戏【圆方树】

正题 题目链接:https://www.luogu.com.cn/problem/P4494 题目大意 给出nnn个点mmm条边的一张无向图&#xff0c;节点有0/10/10/1&#xff0c;每条边可以选择是否取反两边的点。 开始求将所有节点变为000的方案&#xff0c;然后对于每个点询问删去这个点之后的方案 1≤T≤5,1…

福州首届.NET开源社区技术交流会圆满成功

活动总结2018年11月10日周六的下午&#xff0c;在福州蒲公英创新工场举办了福州首届.NET开源社区技术交流会&#xff0c;来自福建省各大科技公司的技术小伙伴齐聚一堂&#xff0c;为了就是能在现场学习到微软跨平台技术.NET Core、微服务以及Azure云服务。在交流会现场&#xf…

【模板】高精度

ACM模板 #include<string> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; struct bign {int d[200010], len;bign() { memset(d, 0, sizeof d); len 1; }bign(int num) { *this num; }big…

POJ3734-Blocks【EGF】

正题 题目链接:http://poj.org/problem?id3734 题目大意 用思种颜色给nnn个格子染色&#xff0c;要求前两种颜色出现偶数次&#xff0c;求方案。 1≤T≤100,1≤n≤1091\leq T\leq 100,1\leq n\leq 10^91≤T≤100,1≤n≤109 解题思路 反正是EGF\text{EGF}EGF的十分入门题了。…

[蓝桥杯][2017年第八届真题]对局匹配

题目描述 小明喜欢在一个围棋网站上找别人在线对弈。这个网站上所有注册用户都有一个积分&#xff0c;代表他的围棋水平。 小明发现网站的自动对局系统在匹配对手时&#xff0c;只会将积分差恰好是K的两名用户匹配在一起。如果两人分差小于或大于K&#xff0c;系统都不会将他们…

codeforce23 E. Tree(高精度+树形dp)

E. Tree 状态表示&#xff1a;fu,jf_{u,j}fu,j​表示以uuu节点的子树&#xff0c;uuu所在连通块大小为jjj时&#xff0c;并且没有算上uuu连通块的贡献的最大值 状态计算&#xff1a; 对于一棵子树vvv来说&#xff0c;显然可以有两种情况 uuu节点与vvv节点不连通&#xff1a;fu…

.NET Core开发者的福音之玩转Redis的又一傻瓜式神器推荐

引子为什么写这篇文章呢&#xff1f;因为.NET Core的生态越来越好了&#xff01;之前玩转.net的时候操作Redis相信大伙都使用过一些组件&#xff0c;但都有一些缺点&#xff0c;如ServiceStack.Redis 是商业版&#xff0c;免费版有限制&#xff1b;StackExchange.Redis 是免费版…

CF891E-Lust【EGF】

正题 题目链接:https://www.luogu.com.cn/problem/CF891E 题目大意 nnn个数字的一个序列aia_iai​&#xff0c;每次随机选择一个让它减去一。然后贡献加上所有其他aia_iai​的乘积。 执行kkk次&#xff0c;求贡献答案。 1≤n≤5000,0≤ai,k≤1091\leq n\leq 5000,0\leq a_i,k…

P2495 [SDOI2011]消耗战(树形dp+虚树)

P2495 [SDOI2011]消耗战 树形dp 状态表示&#xff1a;fuf_ufu​表示以uuu为根的子树中&#xff0c;uuu节点与子树中的关键的“隔开”所需要的最小代价 状态转移&#xff1a; 考虑uuu的一个儿子vvv vvv是关键点&#xff1a;fufuwu→vf_uf_uw_{u\to v}fu​fu​wu→v​vvv不是关键…