本博客题目顺序为:(1)字符串(2 )数组(二维)(3)字符串匹配(暴力BF、KMP)
D - 串结构练习——字符串连接
Description
给定两个字符串string1和string2,将字符串string2连接在string1的后面,并将连接后的字符串输出。
连接后字符串长度不超过110。
Input
输入包含多组数据,每组测试数据包含两行,第一行代表string1,第二行代表string2。
Output
对于每组输入数据,对应输出连接后的字符串,每组输出占一行。
Sample
Input
123 654 abs sfg
Output
123654 abssfg
Hint
#include <iostream>
using namespace std;
int main()
{string s1,s2,s3;
while(cin>>s1>>s2){
s3=s1+s2;
cout<<s3<<endl;
}
return 0;
}
F - 又见回文
Description
“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。现在呢,就是让你判断输入的字符串是否是回文串。
Input
有多组输入,每行输入一串字符,保证字符串长度不会大于 100000,字符串由大小写英文字母和空格组成,以字符串“2013”作为结束标志。
Output
每行输出一个字符串,如果输入是回文串,输出“YES”,否则输出“NO”(注意:判断的时候空格是不作判断的,详见样例)。
Sample
Input
aaaa
ggg g
lozxvxoMJBCHsTXooXTsHCBJMoxvxzol
i am a good acmer
2013
Output
YES
YES
YES
NO
Hint
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s,q;
while(getline(cin,s)&&s!="2013")
{
int l=s.length();
int i;
for(i=0; i<l; i++)
{
if(s[i]==' ')
{
s.erase(s.begin()+i);//删除是空格的位置
i--;//注意删除后 该位置会被其他字符替代 要能重新判断
}
}
q=s;//将s字符串赋值给q
reverse(q.begin(),q.end());//将q字符串进行翻转
if(s==q)
printf("YES\n");
else printf("NO\n");
}
return 0;
}
G - 字符串扩展
Description
Tom有些时候为了记录的方便,常常将一些连续的字符用扩展符'-'简单表示。比如abcdefg可以简写为a-g,即用起始的字符和终止字符中间加上一个扩展符'-'来表示这个字符串。但是为了处理的方便,Tom又必须将这些我们简单记法扩展成原来的字符串。很明显要是人工来做的话必定很麻烦,Tom知道计算机可以帮助他完成这个任务,但是他却不会编程,这的确让他很上火。他知道今天是山东理工大学第三届ACM校赛的日子,届时来自全校的编程爱好者都会来参加比赛,他很兴奋,因为这个困惑他良久的问题终于要被解决了。给你一个含有扩展符'-'的字符串,你的任务就是将他还原成原来的字符串。要求是只处理[a-z]、[A-Z]、[0-9]范围内的字符扩展,即只有当扩展符前后的字符同时是小写字母、大写字母或数字时并且扩展符前面的字符不大于后面的字符才进行扩展,其它情况不进行扩展,原样输出。例如:a-R、D-e、0-b、4-B等字符串都不进行扩展。
Input
第一行是一个正整数T,表示共有T组测试数据(T < 100)。下面的T行,每一行包括一个长度不大于1000的待扩展字符串.
Output
每组测试数据输出一行扩展后的字符串。
Sample
Input
3 ADEa-g-m02 acm-0-5-a-ac-cm-m-A-AC-CM-M Welcometothe3rdACM/ICPCCampusProgrammingContestofSDUT-1-3-A-z-a-Z
Output
ADEabcdefghijklm02 acm-012345-aaccmm-AACCMM Welcometothe3rdACM/ICPCCampusProgrammingContestofSDUT-123-A-z-a-Z
Hint
#include <bits/stdc++.h>
using namespace std;
int main()
{
int i, n, j ;
string s;
cin>>n;
for(i = 0 ; i < n ; i++)
{
cin>>s;
for(j = 0 ; s[j]!='\0' ; j++)//不用算出字符串长度也可
{
if(s[j]=='-' &&( (s[j-1] >= '0' && s[j-1] <= s[j+1] && s[j+1] <= '9') || (s[j-1] >= 'a' && s[j-1] <= s[j+1] && s[j+1] <= 'z') || (s[j-1] >= 'A' && s[j-1] <= s[j+1] && s[j+1] <= 'Z') ) )//包括了a[j-1]==a[j+1]的情况
{
s[j] = s[j-1] + 1 ;//把‘-’直接用扩展出的下一个字符覆盖(省去了单独删除‘-’的操作) 若原来的a[j-1]==a[j+1],由于下面while条件的控制,a[j]不会输出,即‘-’不会输出
while(s[j] < s[j+1])
{
cout<<s[j];
s[j] += 1 ;
}
}
else
cout<<s[j];
}
cout<<endl;
}
return 0;
}
I - bLue的文件查找器
Description
bLue 的电脑里存了各种各样的文件,随着文件越来越多,查找文件也成了一个麻烦事。
现在,他想要查找所有指定格式(扩展名)的文件,不过他并不会使用文件管理器自带的搜索功能,所以他想求你写一个文件查找器,来帮他查找所有指定格式的文件。
Input
输入数据有多组(数据组数不超过 100),到 EOF 结束。
对于每组数据:
- 第一行输入一个整数 n (1 <= n <= 100) 和一个长度不超过 5 的字符串 ex,分别表示文件夹内的文件数量和要查找的文件的扩展名。
- 接下来的 n 行,每行输入一个完整文件名。保证文件名不包含空格且长度不超过 100。
Output
对于每组数据,按照输入顺序输出文件夹内所有扩展名符合查找要求的文件名。
Sample
Input
6 cpp 3717.cpp xunhuansai_daima.zip xunhuansai_jietibaogao.pdf C.cpp bLue.jpg cyk_de_richang.mp4
Output
3717.cpp C.cpp
#include <bits/stdc++.h>
#include <string>
using namespace std;
int main()
{
int n;
int i;
int j;
string s;
string a[200];
while(cin>>n>>s)
{
reverse(s.begin(),s.end());
int length2=s.length();
while(n--)
{
string x;
cin>>x;
int length1=x.length();
reverse(x.begin(),x.end());
i=0;
j=0;
while(i<length1&&j<length2)
{
if(x[i]==s[j])
{
i++;
j++;
}
else break;
}
if(j==length2&&x[j]=='.')//注意扩展名前‘.’的判断!
{
reverse(x.begin(),x.end());
cout<<x<<endl;
}
}
}
return 0;
}
如果不进行‘.’的判断,"xiao wen zi.hhcpp"也会符合 ‘cpp’的匹配,这便就存在错误了。
L - 数据结构实验之数组一:矩阵转置
Description
数组——矩阵的转置
给定一个m*n的矩阵(m,n<=100),求该矩阵的转置矩阵并输出。
Input
输入包含多组测试数据,每组测试数据格式如下:
第一行包含两个数m,n
以下m行,每行n个数,分别代表矩阵内的元素。
(保证矩阵内的数字在int范围之内)
Output
对于每组输出,输出给定矩阵的转置矩阵。两组输出之间用空行隔开。
Sample
Input
2 3 1 2 3 4 5 6 1 1 1
Output
1 4 2 5 3 6 1
Hint
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
int a[200][200];
while(cin>>n>>m)
{
int i,j;
for(i=1; i<=n; i++)
{
for(j=1; j<=m; j++)
{
cin>>a[i][j];
}
}
for(j=1; j<=m; j++)
{
for(i=1; i<=n; i++)
{
cout<<a[i][j]<<' ';
if(i==n)
cout<<endl;
}
}
}
return 0;
}
N - 数据结构实验之数组二:稀疏矩阵
Description
对于一个n*n的稀疏矩阵M(1 <= n <= 1000),采用三元组顺序表存储表示,查找从键盘输入的某个非零数据是否在稀疏矩阵中,如果存在则输出OK,不存在则输出ERROR。稀疏矩阵示例图如下:
Input
连续输入多组数据,每组数据的第一行是三个整数mu, nu, tu(tu<=50),分别表示稀疏矩阵的行数、列数和矩阵中非零元素的个数,数据之间用空格间隔,随后tu行输入稀疏矩阵的非零元素所在的行、列值和非零元素的值,每组数据的最后一行输入要查询的数据k。
Output
输出查询结果,查找成功输出OK,找不到输出ERROR。
Sample
Input
3 5 5
1 2 14
1 5 -5
2 2 -7
3 1 36
3 4 28
36
Output
OK
Hint
#include <bits/stdc++.h>
using namespace std;
int a[2000][2000]= {0};
int main()
{
int n,m,x;
cin>>n>>m>>x;
int flag=0;
while(x--)
{
int h,l,z;
cin>>h>>l>>z;
a[h][l]=z;
}
int i,j;
int e;
cin>>e;
for(i=1; i<=n; i++)
{
for(j=1; j<=m; j++)
{
if(a[i][j]==e)
{
flag=1;
break;
}
}
}
if(flag==1)
cout<<"OK"<<endl;
else cout<<"ERROR"<<endl;
return 0;
}
* * M - 数据结构实验之数组三:快速转置
Description
转置运算是一种最简单的矩阵运算,对于一个m*n的矩阵M( 1 = < m < = 10000,1 = < n < = 10000 ),它的转置矩阵T是一个n*m的矩阵,且T( i , j )=M( j , i )。显然,一个稀疏矩阵的转置仍然是稀疏矩阵。你的任务是对给定一个m*n的稀疏矩阵( m , n < = 10000 ),求该矩阵的转置矩阵并输出。矩阵M和转置后的矩阵T如下图示例所示。
稀疏矩阵M 稀疏矩阵T
Input
连续输入多组数据,每组数据的第一行是三个整数mu, nu, tu(tu <= 50),分别表示稀疏矩阵的行数、列数和矩阵中非零元素的个数,随后tu行输入稀疏矩阵的非零元素所在的行、列值和非零元素的值,同一行数据之间用空格间隔。(矩阵以行序为主序)
Output
输出转置后的稀疏矩阵的三元组顺序表表示。
Sample
Input
3 5 5
1 2 14
1 5 -5
2 2 -7
3 1 36
3 4 28
Output
1 3 36
2 1 14
2 2 -7
4 3 28
5 1 -5
Hint
#include <stdio.h>
#include <stdlib.h>
using namespace std;
struct node
{
int x, y, c;
}a[1005];
int main()
{
int n, m, q, i, j;
while(scanf("%d %d %d", &n, &m, &q) != EOF)
{
for(i = 0; i < q; i++)
{
scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].c);
}
for(i = q - 1; i > 0; i--)
{
for(j = 0; j < i; j++)
{
if(a[j].y > a[j + 1].y || (a[j].y == a[j + 1].y && a[j].x > a[j + 1].x))
{
struct node t = a[j];
a[j] = a[j + 1];
a[j + 1] = t;
}
}
}
for(i = 0; i < q; i++)
{
printf("%d %d %d\n", a[i].y, a[i].x, a[i].c);
}
}
return 0;
}
B - 数据结构实验之串二:字符串匹配
Description
给定两个字符串string1和string2,判断string2是否为string1的子串。
Input
输入包含多组数据,每组测试数据包含两行,第一行代表string1,第二行代表string2,string1和string2中保证不出现空格。(string1和string2大小不超过100字符)
Output
对于每组输入数据,若string2是string1的子串,则输出"YES",否则输出"NO"。
Sample
Input
abc a 123456 45 abc ddd
Output
YES YES NO
Hint
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s1,s2;
while(cin>>s1>>s2)
{
int length1=s1.length();
int length2=s2.length();
int i=0,j=0;
while(i<length1&&j<length2)
{
if(s1[i]==s2[j])
{
i++;
j++;
}
else
{
j=0;
i=i-j+1;
}
}
if(j==length2)
printf("YES\n");
else printf("NO\n");
}
return 0;
}
* * *Next数组、KMP的模板* * *
#define N 200000
int Next[N];
void getnext(string s)
{
int length=s.length();
int i=0,j=-1;
Next[0]=-1;
while(i<length)
{
if(j==-1||s[i]==s[j])
Next[++i]=++j;
else j=Next[j];
}
}
int kmp(string s1,string s2)
{
int len1=s1.length();
int len2=s2.length();
int i=0,j=0;
while(i<len1&&j<len2)
{
if(j==-1||s1[i]==s2[j])
i++,j++;
else j=Next[j];//当j=0时,next[j]就会为-1;
}
if(j==len2)
return i-j+1;
else return -1;
}
A - 数据结构实验之串一:KMP简单应用
Description
给定两个字符串string1和string2,判断string2是否为string1的子串。
Input
输入包含多组数据,每组测试数据包含两行,第一行代表string1(长度小于1000000),第二行代表string2(长度小于1000000),string1和string2中保证不出现空格。
Output
对于每组输入数据,若string2是string1的子串,则输出string2在string1中的位置,若不是,输出-1。
Sample
Input
abc a 123456 45 abc ddd
Output
1 4 -1
Hint
#include <bits/stdc++.h>
using namespace std;
#define N 200000
int Next[N];//不能写成“next”,oj会报编译错误
void getnext(string s)//先得到Next数组;Next数组的获取只与匹配串有关
{
int length=s.length();
int i=0,j=-1;
Next[0]=-1;
while(i<length)
{
if(j==-1||s[i]==s[j])
Next[++i]=++j;
else j=Next[j];
}
}
int kmp(string s1,string s2)
{
int len1=s1.length();
int len2=s2.length();
int i=0,j=0;
while(i<len1&&j<len2)
{
if(j==-1||s1[i]==s2[j]) //当j=0时,next[j]就为-1,所以此判断条件并非无用
i++,j++;
else j=Next[j];//利用Next数组使j不用每次都回溯到最开始;而i不必回溯;
}
if(j==len2)
return i-j+1;//返回匹配到的最初位置
else return -1;
}
int main()
{
string s1,s2;
while(cin>>s1>>s2)
{
getnext(s2);
int y=kmp(s1,s2);
cout<<y<<endl;
}
return 0;
}
C - 数据结构实验之串三:KMP应用
Description
有n个小朋友,每个小朋友手里有一些糖块,现在这些小朋友排成一排,编号是由1到n。现在给出m个数,能不能唯一的确定一对值l和r(l <= r),使得这m个数刚好是第l个小朋友到第r个小朋友手里的糖块数?
Input
首先输入一个整数n,代表有n个小朋友。下一行输入n个数,分别代表每个小朋友手里糖的数量。
之后再输入一个整数m,代表下面有m个数。下一行输入这m个数。
Output
如果能唯一的确定一对l,r的值,那么输出这两个值,否则输出-1
Sample
Input
5 1 2 3 4 5 3 2 3 4
Output
2 4
#include <bits/stdc++.h>
using namespace std;
#define N 2000000 //定义过小也“Wa”
int Next[N];
char s1[N],s2[N];//在主函数中若再同样写一遍,Oj会判为"Wa"
void getnext(char s[])
{
int l=strlen(s);
int i=0,j=-1;
Next[0]=-1;
while(i<l)
{
if(j==-1||s[i]==s[j])
{
Next[++i]=++j;
}
else j=Next[j];
}
}
int kmp(char s1[],char s2[])// 因为要二次判断,所以这里有改变
{
int len1=strlen(s1);
int len2=strlen(s2);//输入字符串的时候要注意从0位置开始存储
int i=0,j=0;
while(i<len1&&j<len2)
{
if(j==-1||s1[i]==s2[j])
i++,j++;
else j=Next[j];
}
if(j==len2)
return i-j+1;
else return -1;
}
int main()
{
int n,m;
cin>>n;
int i;
for(i=0; i<n; i++)//注意要从0位置开始存储
{
cin>>s1[i];
}
cin>>m;
for(i=0; i<m; i++)
{
cin>>s2[i];
}
getnext(s2);
int h;
h=kmp(s1,s2);
if(h!=-1)
{
if(kmp(s1+h,s2)!=-1)//要求要只有一对l,r;
cout<<"-1";
else cout<<h<<" "<<h+m-1;
}
else cout<<"-1";
return 0;
}
E - 学密码学一定得学程序
Description
曾经,ZYJ同学非常喜欢密码学。有一天,他发现了一个很长很长的字符串S1。他很好奇那代表着什么,于是神奇的WL给了他另一个字符串S2。但是很不幸的是,WL忘记跟他说是什么意思了。这个时候,ZYJ不得不求助与伟大的ZP。ZP笑了笑说,这个很神奇的,WL的意思是只要你找到她给你的字符串在那个神奇的字符串的位置,你就会有神奇的发现。ZYJ恍然大悟,原来如此,但是悲剧来了,他竟然不知道怎么找。。。。是的,很囧是不是。所以这时候就需要化身为超级玛丽亚的你现身了,告诉他吧。。。。。。
Input
首先输入一个n。表示有n组测试数据。
每组测试数据有两行。
第一行为字符串S1,长度不大于1000000。
第二行为字符串S2,长度不大于10000,并且长度不小于2。
Output
输出S2在S1的位置。如果有多个位置,只输出第一个位置。
如果找不到,就输出“::>_<::“(不输出双引号)。
Sample
Input
1 ASDFGDF DF
Output
3
Hint
#include <bits/stdc++.h>
#include <string>
using namespace std;
#define N 1e6+100
int Next[2000000];
void getnext(string s)
{
int l=s.length();
int i=0,j=-1;
Next[0]=-1;
while(i<l)
{
if(j==-1||s[i]==s[j])
s[++i]=++j;
else j=Next[j];
}
}
int kmp(string s1,string s2)
{
int len1=s1.length();
int len2=s2.length();
int i=0,j=0;
while(i<len1&&j<len2)
{
if(j==-1||s1[i]==s2[j])
i++,j++;
else j=Next[j];
}
if(j==len2)
return i-j+1;
else return -1;
}
int main()
{
int n;
cin>>n;
while(n--)
{
string s1,s2;
cin>>s1>>s2;
getnext(s2);
int x;
x=kmp(s1,s2);
if(x==-1)
cout<<"::>_<::"<<endl;
else cout<<x<<endl;//没有换行 会"Wa"!
}
return 0;
}
H - cyk追楠神系列一
Description
众所周知,cyk 是个奇特的人,有一天,他终于又做出了一个惊 (zheng) 人 (chang) 的决定,他决定追楠神了!于是 cyk 就写了一封信向楠神表白。但是楠神作为 acm 的大佬,怎么能轻易答应 cyk,他决定对信做一个考察,为此他特意定义了“爱的证据”,“爱的证据”即如果在信里的一个长度等于 k 的字符子串里包含“love”,那么这就是一个“爱的证据”,比如 k=5 时,字符串“i love you”里“ love”和“love ”就是“爱的证据”。 现在,楠神想知道 cyk 写的信里有多少个“爱的证据”,假如“爱的证据”超过 m,那么他就会答应 cyk,如果小于等于 m,那么他就会丑拒。由于 cyk 的字太丑,所以楠神就把这项任务交给了你。
Input
第一行输入 t (1 <= t <= 100),代表有 t 组输入数据。
每组数据第一行输入 m, k (1 <= m, k <= 10^3)。
第二行输出一个字符串 a,长度不超过 10^3。
Output
每组输出占一行,假如楠神可以答应 cyk,就输出“congratulation”,如果不能就输出“too ugly to accept”。
Sample
Input
1 1 5 i love you
Output
congratulation
Hint
#include <bits/stdc++.h>
#include <string>
using namespace std;
#define N 1e6+100
int main(){
int t;
cin>>t;
while(t--){
int m,k;
cin>>m>>k;
string s;
getchar();//
getline(cin,s);//不能用cin;cin只读到空白格,而getline整行读入
int l=s.length();
int cnt=0;
int i,j;
for(i=0;i<l-k+1;i++){
for(j=i;j<=i+k-4;j++){
if(s[j]=='l'&&s[j+1]=='o'&&s[j+2]=='v'&&s[j+3]=='e'){
cnt++;
break;
}
}
}
if(m<cnt)
cout<<"congratulation"<<endl;
else cout<<"too ugly to accept"<<endl;
}
return 0;
}
* * *J - Power Strings
Description
Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "abcdef". If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = "" (the empty string) and a^(n+1) = a*(a^n).
Input
Each test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.
Output
For each s you should print the largest n such that s = a^n for some string a.
Sample
Input
abcd aaaa ababab .
Output
1 4 3
Hint
This problem has huge input, use scanf instead of cin to avoid time limit exceed.
#include <bits/stdc++.h>
#include <string>
using namespace std;
#define N 1e6+100
int Next[2000000];
void getnext(string s)
{
int i=0,j=-1;
int len=s.length();
Next[0]=-1;
while(i<len)
{
if(j==-1||s[i]==s[j])
{
Next[++i]=++j;
}
else j=Next[j];
}
}
int main()
{
string s;
while(cin>>s&&s[0]!='.')
{
int len=s.length();
getnext(s);
if(len%(len-Next[len])==0)
{
int y=len/(len-Next[len]);//(len-Next[len])为子串的长度;
cout<<y<<endl;
}
else cout<<"1"<<endl;
}
return 0;
}
* * *K - Period
Description
For each prefix of a given string S with N characters (each character has an
ASCII code between 97 and 126, inclusive), we want to know whether the prefix
is a periodic string. That is, for each i (2 ≤ i ≤ N) we want to know the largest K
> 1 (if there is one) such that the prefix of S with length i can be written as AK ,
that is A concatenated K times, for some string A. Of course, we also want to
know the period K.
Input
The input file consists of several test cases. Each test case consists of two
lines. The first one contains N (2 <= N <= 1 000 000) – the size of the string S.
The second line contains the string S. The input file ends with a line, having the
number zero on it.
Output
For each test case, output “Test case #” and the consecutive test case
number on a single line; then, for each prefix with length i that has a period K >
1, output the prefix size i and the period K separated by a single space; the
prefix sizes must be in increasing order. Print a blank line after each test case.
Sample
Input
3 aaa 12 aabaabaabaab 0
Output
Test case #1 2 2 3 3 Test case #2 2 2 6 2 9 3 12 4
Hint
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 100;
char s[N];
int Next[N];
void get_Next(char *s)
{
int n = strlen(s);
int j = 0, k = -1;
Next[0] = -1;
while(j < n)
{
if(k == -1 || s[j] == s[k])
{
Next[++j] = ++k;
}
else k = Next[k];
}
}
int main()
{
ios::sync_with_stdio(0);
int n, j = 0;
while(cin >> n && n)
{
for(int i = 0; i < n; i++)
{
cin >> s[i];
}
get_Next(s);
j++;
cout << "Test case #" << j << endl;
for(int i = 2; i <= n; i++)
{
if(i % (i - Next[i]) == 0 && i != (i - Next[i]))
{
cout << i << " " << i / (i - Next[i]) << endl;
}
}
}
return 0;
}