学习文档:http://www.cnblogs.com/c-cloud/p/3224788.html
1.Number Sequence
题意:给T组数据,每组有长度为n和m的母串和模式串。判断模式串是否是母串的子串,如果是输出最先匹配完成的位置,否则输出-1.
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1000003;
int t[N],p[N],i,n,m,ne[N],T;
int read(){
char c;int x=0,f=1;
do{c=getchar();if(c=='-')f=-1;}while(c<48||c>57);
do x=(x<<1)+(x<<3)+(c^48),c=getchar();while(c>=48&&c<=57);
return f*x;
}
void make(){
for (int i=1,j=0;i<m;i++){
while (j && p[i]!=p[j]) j=ne[j-1];
if (p[i]==p[j]) j++;
ne[i]=j;
}
}
int kmp(){
make();
for (int i=0,j=0;i<n;i++){
while (j && t[i]!=p[j]) j=ne[j-1];
if (t[i]==p[j]) j++;
if (j==m) return i-m+2;
}
return -1;
}
int main(){
scanf("%d",&T);
while (T--){
n=read();m=read();
for (i=0;i<n;i++) t[i]=read();
for (i=0;i<m;i++) p[i]=read();
printf("%d\n",kmp());
}
}
2. Oulipo
题意:给T组数据,每组有两个字符串按顺序分别为模式串和母串。判断模式串在母串中出现的次数。模式串在母串中是可以相互覆盖的。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1000003,M=10003;
int ne[M],T,n,m;
char p[M],t[N];
void make(){
for (int i=1,j=0;i<m;i++){
while (j && p[i]!=p[j]) j=ne[j-1];
if (p[i]==p[j]) j++;
ne[i]=j;
}
}
int kmp(){
make();
int sum=0;
for (int i=0,j=0;i<n;i++){
while (j && t[i]!=p[j]) j=ne[j-1];
if (t[i]==p[j]) j++;
if (j==m) sum++;
}
return sum;
}
int main(){
scanf("%d",&T);
while (T--){
scanf("%s%s",p,t);
n=strlen(t);m=strlen(p);
printf("%d\n",kmp());
}
}
3.剪花布条
题意:输入母串和模式串,以’#‘为结束。剪纸花,从母串中减去模式串问能剪出多少。这就意味着求解模式串的数量时不能重叠覆盖
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1003;
int ne[N],T,n,m;
char p[N],t[N];
void make(){
for (int i=1,j=0;i<m;i++){
while (j && p[i]!=p[j]) j=ne[j-1];
if (p[i]==p[j]) j++;
ne[i]=j;
}
}
int kmp(){
make();
int sum=0;
for (int i=0,j=0;i<n;i++){
while (j && t[i]!=p[j]) j=ne[j-1];
if (t[i]==p[j]) j++;
if (j==m) sum++,j=0;
}
return sum;
}
int main(){
while (~scanf("%s",t)){
if (t[0]=='#') return 0;
scanf("%s",p);
n=strlen(t);m=strlen(p);
printf("%d\n",kmp());
}
}
4.Cyclic Nacklace
题意:给T组数据,每组有一个字符串,只能在字符串的前面和后面增加字符,不能再中间增加,求要使这个字符串是周期循环的且周期的次数大于一,至少需要增加的字符数量。注意这个字符串是个手链,也就是说是增加字符后首位相连是周期的即可
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=100003;
int T,n,i,j,ne[N],t;
char s[N];
int main(){
scanf("%d",&T);
while (T--){
scanf("%s",s);
n=strlen(s);
for (i=1,j=0;i<n;i++){
while (j && s[i]!=s[j]) j=ne[j-1];
if (s[i]==s[j]) j++;
ne[i]=j;
}
if (!ne[n-1]){
printf("%d\n",n);
continue;
}
t=n-ne[n-1];
printf("%d\n",n%t==0?0:t-n%t);
}
}
5.Period
题意:给字符串的长度和一个字符串。读到eof。求每个字符串中在i之前的位置是循环的且次数大于1,求这个位置i以及循环的次数
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1000003;
int t,n,ne[N],i,j,T;
char s[N];
int main(){
while (1){
scanf("%d",&n);
if (!n) return 0;
printf("Test case #%d\n",++T);
scanf("%s",s);
for (i=1,j=0;i<n;i++){
while (j && s[i]!=s[j]) j=ne[j-1];
if (s[i]==s[j]) j++;
ne[i]=j;
t=i+1-ne[i];
if ((i+1)%t==0 && i+1>t) printf("%d %d\n",i+1,(i+1)/t);
}
putchar('\n');
}
}
6.power strings
题意:每组给以个字符串,一直读到’.’.字符串s = a^n,及都是由a构成的,求n的值
做法:求最小循环节,如果整除,那除得的数及为ans。如果不整除ans = 1
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=1000003;
int n,i,j,ne[N],t;
char s[N];
int main(){
while (1){
scanf("%s",s);
if (s[0]=='.') return 0;
n=strlen(s);
for (i=1,j=0;i<n;i++){
while (j && s[i]!=s[j]) j=ne[j-1];
if (s[i]==s[j]) j++;
ne[i]=j;
}
t=n-ne[n-1];
printf("%d\n",n%t==0?n/t:1);
}
}
7.Seek the Name, Seek the Fame
题意:每组一个字符串,读到eof结束。寻找i使得字符串的前缀等于后缀
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=400003;
int ne[N],m,i,ans[N],cnt,t;
char s[N];
void make(){
for (int i=1,j=0;i<m;i++){
while (j && s[i]!=s[j]) j=ne[j-1];
if (s[i]==s[j]) j++;
ne[i]=j;
}
}
int main(){
while (~scanf("%s",s)){
m=strlen(s);
make();
cnt=0;t=ne[m-1];
while (t){
ans[cnt++]=t;
t=ne[t-1];
}
for (i=cnt-1;i>=0;i--) printf("%d ",ans[i]);
printf("%d\n",m);
}
}
8.Blue Jeans
题意:T组数据,每组m个DNA序列,每个DNA序列都有60个字符,且只由ACGT几个字母构成。判断m个DNA序列最长公共的子串是什么?如果有相同长度的公共子串,则输出字典序最小的。如果小于3输出“no ……”,大于等于3输出字符串
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=61,M=1802;
int vis[M],i,j,n,m,ne[M][N],cnt,k,T,l[M];
char s1[N],s[M][N];
bool cmp(int x,int y){
if (l[x]!=l[y]) return l[x]>l[y];
for (int i=0;i<l[x];i++)
if (s[x][i]!=s[y][i]) return s[x][i]<s[y][i];
}
void make(int t){
for (int i=1,j=0;i<l[t];i++){
while (j && s[t][i]!=s[t][j]) j=ne[t][j-1];
if (s[t][i]==s[t][j]) j++;
ne[t][i]=j;
}
}
int kmp(int t){
int n=strlen(s1);
if (l[t]>n) return 1;
for (int i=0,j=0;i<n;i++){
while (j && s[t][j]!=s1[i]) j=ne[t][j-1];
if (s[t][j]==s1[i]) j++;
if (j==l[t]) return 0;
}
return 1;
}
int main(){
scanf("%d",&T);
while (T--){
scanf("%d%s",&m,s1);
n=strlen(s1);
memset(vis,0,sizeof(vis));
memset(s,0,sizeof(s));
cnt=0;
for (i=0;i<n;i++)
for (j=i+2;j<n;j++){
for (k=i;k<=j;k++) s[cnt][k-i]=s1[k];
l[cnt]=j-i+1;
make(cnt);cnt++;
}
for (i=1;i<m;i++){
scanf("%s",s1);
for (j=0;j<cnt;j++)
if (!vis[j]) vis[j]=kmp(j);
}
k=-1;
for (i=0;i<cnt;i++)
if (!vis[i] && (k==-1 || cmp(i,k))) k=i;
printf("%s\n",k!=-1?s[k]:"no significant commonalities");
}
}
9.Simpsons’ Hidden Talents
题意:每组给两个字符串以eof结尾。求s1的前缀,等于s2后缀的长度.如果长度不是零空格之后输出相同的部分,否则只输出零即可
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=50003;
int ne[N],i,l,n,m;
char s1[N],s2[N];
void make(){
for (int i=0,j=1;j<m;j++){
while (i && s1[i]!=s1[j]) i=ne[i-1];
if (s1[i]==s1[j]) i++;
ne[j]=i;
}
}
int kmp(){
make();
int i=0,j=0;
for (;j<m;j++){
while (i && s1[i]!=s2[j]) i=ne[i-1];
if (s1[i]==s2[j]) i++;
}
return i;
}
int main(){
while (~scanf("%s",s1)){
scanf("%s",s2);
n=strlen(s1);m=strlen(s2);
l=kmp();
for (i=0;i<l;i++) putchar(s1[i]);
if (l) putchar(' ');
printf("%d\n",l);
}
}
10.Count the string
题意:给T组数据,每组数据给一个长度为n的字符串s。求字符串每个前缀出现的次数,结果mod 10007
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=200003;
int T,n,i,sum,f[N],ne[N],j;
char s[N];
int main(){
scanf("%d",&T);
while (T--){
scanf("%d%s",&n,s);
for (i=1,j=0;i<n;i++){
while (j && s[i]!=s[j]) j=ne[j-1];
if (s[i]==s[j]) j++;
ne[i]=j;
}
f[0]=0;sum=0;
for (i=0;i<n;i++){
f[i+1]=f[ne[i]]+1;
sum+=f[i+1];
}
printf("%d\n",sum%10007);
}
}
11.Clairewd’s message
题意:给T组数据,每组数据第一行是26个字母表示[a,z]所对应的密文字母。第二行的字符串由两部分组成,第一部分是密文部分,第二部分是明文部分。明文部分可能是不完整的,也可能是完整的输出完整的明文部分
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=100003;
int ne[N],i,j,ans,T,l;
char str[28],s1[N],s2[N];
void make(char *s){
int n=strlen(s);
for (int i=1,j=0;i<n;i++){
while (j && s[i]!=s[j]) j=ne[j];
if (s[i]==s[j]) j++;
ne[i]=j;
}
}
int kmp(char *s,char *t){
make(t);
int n=strlen(s),i=0,j=0;
for (;i<n;i++){
while (j && s[i]!=t[j]) j=ne[j];
if (s[i]==t[j]) j++;
}
return j;
}
int main(){
scanf("%d",&T);
while (T--){
scanf("%s%s",str,s1);
printf("%s",s1);
l=strlen(s1);
strcpy(s2,s1+(l+1)/2);
for (i=0;s1[i];i++)
for (j=0;j<26;j++)
if (s1[i]==str[j]){
s1[i]='a'+j;
break;
}
ans=kmp(s2,s1);
for (i=ans;i<l-ans;i++) putchar(s1[i]);
putchar('\n');
}
}
12. Period II
题意:每组n个字符串,以eof结束。求每个字符串中满足S[i]=S[i+P] for i in [0..SIZE(S)-p-1],的位置。
#include<cstdio>
#include<cstring>
const int N=1000003;
int Case,T,l,i,j,t,ne[N],ans[N],cnt;
char s[N],c;
int main(){
scanf("%d",&T);
while (T--){
scanf("%s",s);
l=strlen(s);
for (i=1,j=0;i<l;i++){
while (j && s[i]!=s[j]) j=ne[j-1];
if (s[i]==s[j]) j++;
ne[i]=j;
}
t=ne[l-1];cnt=0;
while (t){
ans[cnt++]=l-t;
t=ne[t-1];
}
printf("Case #%d: %d\n",++Case,cnt+1);
for (i=0;i<cnt;i++) printf("%d ",ans[i]);
printf("%d\n",l);
}
}
13.Theme Section
题意:n个字符串,每个字符串都可以写成EAEBE的形式,其中E可以为空,寻找最长的E
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=1000003;
int T,l,ne[N];
char s[N];
void make(){
for (int i=1,j=0;i<l;i++){
while (j && s[i]!=s[j]) j=ne[j-1];
if (s[i]==s[j]) j++;
ne[i]=j;
}
}
int kmp(){
make();
for (int i=ne[l-1];i;i=ne[i-1])
for (int j=i<<1;j<=l-i;j++)
if (ne[j-1]==i) return i;
return 0;
}
int main(){
scanf("%d",&T);
while (T--){
scanf("%s",s);
l=strlen(s);
printf("%d\n",kmp());
}
}