字符串专题总结
来源:互联网 发布:淘宝换购拍下 编辑:程序博客网 时间:2024/06/05 19:11
这部分主要涉及了对AC自动机的理解,和KMP的理解
注意点:模板~!!
AC自动机模板 和KMP的模板
字典树的建立
KMP next 数组也是非常重要
next数组性质:
1、根据KMP的next函数的性质,已知字符串t第K个字符的next[k],那么d=k-next[k],如果k%d==0,那么t[1……k]最多可均匀的分成k/d份。也就是可以生成一个长度为d的重复度为k/d的字串
A - Oulipo_KMP
The French author Georges Perec (1936–1982) once wrote a book, La disparition, without the letter 'e'. He was a member of the Oulipo group. A quote from the book:
Tout avait Pair normal, mais tout s’affirmait faux. Tout avait Fair normal, d’abord, puis surgissait l’inhumain, l’affolant. Il aurait voulu savoir où s’articulait l’association qui l’unissait au roman : stir son tapis, assaillant à tout instant son imagination, l’intuition d’un tabou, la vision d’un mal obscur, d’un quoi vacant, d’un non-dit : la vision, l’avision d’un oubli commandant tout, où s’abolissait la raison : tout avait l’air normal mais…
Perec would probably have scored high (or rather, low) in the following contest. People are asked to write a perhaps even meaningful text on some subject with as few occurrences of a given “word” as possible. Our task is to provide the jury with a program that counts these occurrences, in order to obtain a ranking of the competitors. These competitors often write very long texts with nonsense meaning; a sequence of 500,000 consecutive 'T's is not unusual. And they never use spaces.
So we want to quickly find out how often a word, i.e., a given string, occurs in a text. More formally: given the alphabet {'A', 'B', 'C', …, 'Z'} and two finite strings over that alphabet, a word W and a text T, count the number of occurrences of W in T. All the consecutive characters of W must exactly match consecutive characters of T. Occurrences may overlap.
The first line of the input file contains a single number: the number of test cases to follow. Each test case has the following format:
- One line with the word W, a string over {'A', 'B', 'C', …, 'Z'}, with 1 ≤ |W| ≤ 10,000 (here |W| denotes the length of the string W).
- One line with the text T, a string over {'A', 'B', 'C', …, 'Z'}, with |W| ≤ |T| ≤ 1,000,000.
For every test case in the input file, the output should contain a single number, on a single line: the number of occurrences of the word W in the text T.
3BAPCBAPCAZAAZAZAZAVERDIAVERDXIVYERDIAN
130
简单的KMP匹配
#include<stdio.h>#include<iostream>#include<cmath>#include<stdlib.h>#include<string>#include<cstring>#define MOD 1000000007typedef long long ll;using namespace std;const int N = 1000005;void kmp_pre(char x[],int m,int next[]){ int i,j; j=next[0]=-1; i=0; while(i<m) { while(-1!=j && x[i]!=x[j]) j=next[j]; next[++i]=++j; }}int KMP_Count(char x[],int m,char y[],int n){ int next1[N*2]; memset(next1,0,sizeof(next1)); int i,j; int ans=0; kmp_pre(x,m,next1); i=j=0; while(i<n) { while(-1!=j && y[i]!=x[j]) j=next1[j]; i++;j++; if(j>=m) { ans++; j=next1[j]; } } return ans;}char w[10005];char s[1000005];int t;int main(){// freopen("data.txt","r",stdin); scanf("%d",&t); while(~scanf("%s %s",w,s)){ printf("%d\n",KMP_Count(w,strlen(w),s,strlen(s))); } return 0;}
B - 统计难题_字典树
注意:本题只有一组测试数据,处理到文件结束.
bananabandbeeabsoluteacmbabbandabc
2310
字典树入门题,先建一个字典树,然后遍历求解就好。
#include <cstdio>#include <iostream>#include <cmath>#include <cstdlib>#include <string>#include <cstring>#define MOD 1000000007typedef long long ll;using namespace std;const int N = 1000005;struct Trie{ int v;//v可以根据实际情况任意变化,在这里v是每个字母的次数;Trie *next[26];};Trie root;void createTrie(char *str)//建立字典树;{int len=strlen(str);Trie *p=&root,*q;for(int i=0;i<len;i++){int id=str[i]-'a';if(p->next[id]==NULL){q=(Trie *)malloc(sizeof(root));//申请一块新内存;q->v=1;//v遇到新字母每一层都初始化为1;for(int j=0;j<26;j++)q->next[j]=NULL;p->next[id]=q;p=p->next[id];}else{p->next[id]->v++;//当第一个输入的字符串和后面又相等的时候,v++;p=p->next[id];}}}int findTrie(char *str)//在字典树里查询;{int len=strlen(str);Trie *p=&root;for(int i=0;i<len;i++){int id=str[i]-'a';p=p->next[id];if(p==NULL)return 0;}return p->v;//相同的字母个数;}char str[1000000];int t;int main(){// freopen("data.txt","r",stdin); while(gets(str) && str[0]!='\0'){createTrie(str);}while(cin>>str){int ans=findTrie(str);cout<<ans<<endl;} return 0;}
C - Keywords Search
Wiskey also wants to bring this feature to his image retrieval system.
Every image have a long description, when users type some keywords to find the image, the system will match the keywords with description of image and show the image which the most keywords be matched.
To simplify the problem, giving you a description of image, and some keywords, you should tell me how many keywords will be match.
Each case will contain two integers N means the number of keywords and N keywords follow. (N <= 10000)
Each keyword will only contains characters 'a'-'z', and the length will be not longer than 50.
The last line is the description, and the length will be not longer than 1000000.
15shehesayshrheryasherhs
3
入门AC自动机
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <iomanip>#include <algorithm>#include <climits>#include <cstring>#include <string>#include <set>#include <map>#include <queue>#include <stack>#include <vector>#include <list>#define rep(i,m,n) for(int i=m;i<=n;i++)#define rsp(it,s) for(set<int>::iterator it=s.begin();it!=s.end();it++)const int inf_int = 2e9;const long long inf_ll = 2e18;#define inf_add 0x3f3f3f3f#define MOD 1000000007#define pb push_back#define mp make_pair#define fi first#define se second#define pi acos(-1.0)#define pii pair<int,int>#define Lson L, mid, rt<<1#define Rson mid+1, R, rt<<1|1const int maxn=5e2+10;using namespace std;typedef vector<int> vi;typedef long long ll;typedef unsigned long long ull;inline int read(){int ra,fh;char rx;rx=getchar(),ra=0,fh=1; while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();if(rx=='-') fh=-1,rx=getchar();while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48, rx=getchar();return ra*fh;}//#pragma comment(linker, "/STACK:102400000,102400000")ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p;p=p*p;q>>=1;}return f;}int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};const int N = 1e6+5;const int M = 27;class Trie{public: //next数组存储树 //fail数组存储下一个要匹配的节点号 //end数组主要是用来标记一个模式串结尾 int next[N][M],fail[N],end[N]; int root,L; int newnode() { for(int i = 0;i < M;i++)//每一个节点对应0-128中的任意一个。 next[L][i] = -1; end[L++] = 0;//表示下面没有节点 初始化,如果是记录次数,就赋0 还可以赋任意的数, return L-1; } void init() { L = 0; root = newnode(); } void insert(char s[],int id) { int len = strlen(s); int now = root; for(int i = 0;i < len;i++) { int k =s[i]-'a'; if(next[now][k] == -1) next[now][k] = newnode(); now=next[now][k]; }// end[now]=id;//记录当前匹配单词的节点 end[now]++;//也可以用匹配单词结束后来记录次数 } //BFS求fail void build() { queue<int>Q; fail[root] = root; //初始化root及其子节点 for(int i = 0;i < M;i++) if(next[root][i] == -1) next[root][i] = root; else { fail[next[root][i]] = root; Q.push(next[root][i]); } while(!Q.empty()) { int now = Q.front(); Q.pop(); //遍历节点 for(int i = 0;i < M;i++) if(next[now][i] == -1) //不需要失配函数,对所有转移一视同仁 next[now][i] = next[fail[now]][i]; else { fail[next[now][i]] = next[fail[now]][i]; Q.push(next[now][i]); } } } void query(char buf[]) { int ans=0; int len = strlen(buf); int now = root; bool flag = false; for(int i = 0;i < len;i++) { int k =buf[i]-'a'; now = next[now][k]; int temp = now; //其会匹配多个模式串 while(temp != root) { ans+=end[temp]; end[temp] = 0; temp = fail[temp]; } } printf("%d\n",ans); }};char buf[1000005];Trie ac;int T;int main(){// freopen("data.txt","r",stdin); int n,m; scanf("%d",&T); for(int k=0;k<T;k++) { scanf("%d",&n); ac.init(); for(int i = 1;i <= n;i++) { scanf("%s",buf); ac.insert(buf,i); } ac.build(); scanf("%s",buf); ac.query(buf); } return 0;}
D - Power Strings
abcdaaaaababab.
143
这是一个kmp比较神奇的例子
根据KMP的next函数的性质,已知字符串t第K个字符的next[k],那么d=k-next[k],如果k%d==0,那么t[1……k]最多可均匀的分成k/d份。也就是可以生成一个长度为d的重复度为k/d的字串。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <iomanip>#include <algorithm>#include <climits>#include <cstring>#include <string>#include <set>#include <map>#include <queue>#include <stack>#include <vector>#include <list>#define rep(i,m,n) for(int i=m;i<=n;i++)#define rsp(it,s) for(set<int>::iterator it=s.begin();it!=s.end();it++)const int inf_int = 2e9;const long long inf_ll = 2e18;#define inf_add 0x3f3f3f3f#define MOD 1000000007#define pb push_back#define mp make_pair#define fi first#define se second#define pi acos(-1.0)#define pii pair<int,int>#define Lson L, mid, rt<<1#define Rson mid+1, R, rt<<1|1const int maxn=5e2+10;using namespace std;typedef vector<int> vi;typedef long long ll;typedef unsigned long long ull;inline int read(){int ra,fh;char rx;rx=getchar(),ra=0,fh=1; while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();if(rx=='-') fh=-1,rx=getchar();while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48, rx=getchar();return ra*fh;}//#pragma comment(linker, "/STACK:102400000,102400000")ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p;p=p*p;q>>=1;}return f;}int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};const ll INF = 1e18+5;int next1[1000005];void kmp_pre(char x[],int m,int next[]){ int i,j; j=next[0]=-1; i=0; while(i<m) { while(-1!=j && x[i]!=x[j]) j=next[j]; //根据当前计算下一个字符的next //abab //aba -> b next[++i]=++j; }}int KMP_Count(char x[],int m,char y[],int n){ int next1[N*2]; memset(next1,0,sizeof(next1)); int i,j; int ans=0; kmp_pre(x,m,next1); i=j=0; //i为左指针 while(i<n) { while(-1!=j && y[i]!=x[j]) j=next1[j]; i++;j++; if(j>=m) { ans++; j=next1[j]; } } return ans;}char buf[1000005];int main(){// freopen("data.txt","r",stdin); while(~scanf("%s",buf)) { memset(next1,0,sizeof(next1)); if(buf[0]=='.'&&buf[1]=='\0') break; int len = strlen(buf); kmp_pre(buf,len,next1); int m = len-next1[len]; if(len%m==0) {// int f= 0;// for(int i=len-1;i>m;i-=m)// {// if(i-next1[i]!=m)// {// f =1;// break;// }// }//// if(f)// {// printf("%d\n",1);// }// else { printf("%d\n",len/m); } } else { printf("%d\n",1); }// for(int i=0;i<=len;i++)// {// cout << next1[i]<<" ";// }// cout <<endl; } return 0;}
F - Knight Moves
Of course you know that it is vice versa. So you offer him to write a program that solves the "difficult" part.
Your job is to write a program that takes two squares a and b as input and then determines the number of knight moves on a shortest route from a to b.
e2 e4a1 b2b2 c3a1 h8a1 h7h8 a1b1 c3f6 f6
To get from e2 to e4 takes 2 knight moves.To get from a1 to b2 takes 4 knight moves.To get from b2 to c3 takes 2 knight moves.To get from a1 to h8 takes 6 knight moves.To get from a1 to h7 takes 5 knight moves.To get from h8 to a1 takes 6 knight moves.To get from b1 to c3 takes 1 knight moves.To get from f6 to f6 takes 0 knight moves.
一个简单的BFS
。。。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <iomanip>#include <algorithm>#include <climits>#include <cstring>#include <string>#include <set>#include <map>#include <queue>#include <stack>#include <vector>#include <list>#define rep(i,m,n) for(int i=m;i<=n;i++)#define rsp(it,s) for(set<int>::iterator it=s.begin();it!=s.end();it++)const int inf_int = 2e9;const long long inf_ll = 2e18;#define inf_add 0x3f3f3f3f#define pb push_back#define mp make_pair#define fi first#define se second#define pi acos(-1.0)#define pii pair<int,int>#define Lson L, mid, rt<<1#define Rson mid+1, R, rt<<1|1using namespace std;typedef vector<int> vi;typedef long long ll;typedef unsigned long long ull;inline int read(){int ra,fh;char rx;rx=getchar(),ra=0,fh=1;while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();if(rx=='-')fh=-1,rx=getchar();while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh;}//#pragma comment(linker, "/STACK:102400000,102400000")ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p;p=p*p;q>>=1;}return f;}//int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};const int maxn=1e6+10;bool mm[10][10];struct node{ int x; int y; int step;};int dir[8][2] = {-2,1,-1,2,1,2,2,1,2,-1,1,-2,-1,-2,-2,-1};//骑士移动的8个方位char s1[3];char s2[3];int check(int x,int y){ if(x<0 || y<0 || x>=8 || y>=8 || mm[x][y]) return 1; return 0;}int bfs(int x1,int y1,int x2,int y2){ if(x1==x2&&y1==y2) return 0; node nt,cur ; nt.x = x1; nt.y = y1; nt.step = 0; queue<node> q; q.push(nt); mm[nt.x][nt.y] = 1; while(!q.empty()) { nt = q.front(); q.pop(); for(int i=0;i<8;i++) { int xx = nt.x + dir[i][0]; int yy = nt.y + dir[i][1]; if(check(xx,yy)) continue; if(xx==x2&&yy==y2) { return nt.step+1; } mm[xx][yy] = 1; cur.x = xx; cur.y = yy; cur.step = nt.step + 1; q.push(cur); } } return 0;}int main(){// freopen("data.txt","r",stdin); while(~scanf("%s%s",s1,s2)) { memset(mm,0,sizeof(mm)); int ans = 0; int x1 = s1[0] - 'a'; int y1 = s1[1] - '1'; int x2 = s2[0] - 'a'; int y2 = s2[1] - '1'; ans = bfs(x1,y1,x2,y2); printf("To get from %s to %s takes %d knight moves.\n",s1,s2,ans); }}
number zero on it.
3aaa12aabaabaabaab0
Test case #12 23 3Test case #22 26 29 312 4
与D题原理相同
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <iomanip>#include <algorithm>#include <climits>#include <cstring>#include <string>#include <set>#include <map>#include <queue>#include <stack>#include <vector>#include <list>#define rep(i,m,n) for(int i=m;i<=n;i++)#define rsp(it,s) for(set<int>::iterator it=s.begin();it!=s.end();it++)const int inf_int = 2e9;const long long inf_ll = 2e18;#define inf_add 0x3f3f3f3f#define pb push_back#define mp make_pair#define fi first#define se second#define pi acos(-1.0)#define pii pair<int,int>#define Lson L, mid, rt<<1#define Rson mid+1, R, rt<<1|1using namespace std;typedef vector<int> vi;typedef long long ll;typedef unsigned long long ull;inline int read(){int ra,fh;char rx;rx=getchar(),ra=0,fh=1;while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();if(rx=='-')fh=-1,rx=getchar();while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh;}//#pragma comment(linker, "/STACK:102400000,102400000")ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p;p=p*p;q>>=1;}return f;}//int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};const int maxn=1e6+10;void kmp_pre(char x[],int m,int next[]){ int i,j; j=next[0]=-1; i=0; while(i<m) { while(-1!=j && x[i]!=x[j]) j=next[j]; next[++i]=++j; }}int n;char s[maxn];int cas = 0;int main(){ int next1[maxn*2];// freopen("data.txt","r",stdin); while(~scanf("%d",&n)) { if(n==0) break; cas++; scanf("%s",s); printf("Test case #%d\n",cas); memset(next1,0,sizeof(next1)); kmp_pre(s,n,next1); for(int i=1;i<=n;i++) { int len = i;// cout <<"next: " <<next1[i]<<endl; if(len%(len-next1[i])==0&&len!=len-next1[i]) { printf("%d %d\n",i,len/(len-next1[i])); } } puts(""); }}
- 字符串专题总结
- 字符串专题
- 字符串专题
- 字符串专题
- 字符串专题
- 专题:字符串
- 字符串专题
- 字符串专题
- [C#基础知识系列]专题六:C#字符串操作总结
- SG专题:博弈专题总结
- PHP 截取字符串专题
- PHP 截取字符串专题
- PHP 截取字符串专题
- PHP 截取字符串专题
- PHP 截取字符串专题
- 面试题目 字符串专题
- PHP 截取字符串专题
- js字符串处理专题
- equals、“==”与hashCode的介绍
- Mac设置环境变量
- C++ 标准模板库STL的数据结构
- Python中callable函数如何使用?
- linux之vim常用命令
- 字符串专题总结
- 欢迎使用CSDN-markdown编辑器
- Android 内存泄漏和内存溢出
- NBUT
- poj_1887
- jvm知识点
- 性能优化
- JAVA_多线程_单例模式
- .net core借助sendCloud实现邮件验证码发送