涉及的知识点
本周练习主要涉及字符串
已完成题目 CodeForce:219A、1462B、520A、1367A、978B、855A、1384A、785A、1473B;POJ:1035、1936、2513、3349、2503
未完成题目 CodeForce:1451B、1478B、1476D、1478A;POJ:3080、3274、2151、1840、2002
已完成题目整理
CodeForce 219A
题目大意:给出一个数k,再给出一个字符串,判断该字符串能否通过k个相同的字符串来组成
思路:判断每种字符能否整除k即可
代码
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
int k;
char str[1212];
int alpha[26],len;
int main()
{
scanf("%d",&k);
getchar();
scanf("%s",str);
len=strlen(str);
for(int i=0; i<len; i++)
alpha[str[i]-'a']++;
for(int i=0; i<26; i++)
if(alpha[i]%k)
{
printf("-1\n");
return 0;
}
for(int t=0; t<k; t++)
for(int i=0; i<26; i++)
for(int j=1; j<=alpha[i]/k; j++)
printf("%c",'a'+i);
putchar('\n');
return 0;
}
CodeForce 520A
题目大意:判断给出的字符串是否包括所有的26个字母
思路:略
代码
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;
int n;
bool alphabet[26];
char ch;
int main()
{
scanf("%d",&n);
getchar();
while(n--)
{
ch=getchar();
alphabet[(ch=tolower(ch))-'a']=true;
}
for(int i=0; i<26; i++)
if(!alphabet[i])
{
printf("NO");
return 0;
}
printf("YES");
return 0;
}
CodeForce 1367A
题目大意:给出一个字符串,它由多个只用两个字母的字符串合成而来,如abac分解成ab、ba、ac后合成abbaac,求输入字符串的初始形式
思路:直接去掉特定位置字符即可
代码
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
int t;
int main()
{
cin >>t;
while(t--)
{
char s[101]= {'\0'};
cin >>s;
int len=strlen(s);
if(len==2)
{
cout <<s<<endl;
continue;
}
for(int i=1; i<len; i+=2)
if(i!=len-1)
s[i]='\0';
for(int i=0; i<len; i++)
if(s[i])
cout <<s[i];
cout <<endl;
}
return 0;
}
CodeForce 978B
题目大意:给出一个字符串,不允许出现多于3个x相连,如果出现,判断删除多少个字符能满足条件
思路:直接模拟即可
代码
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;
int n,op,ans;
char ch;
int main()
{
scanf("%d",&n);
getchar();
while(n--)
{
scanf("%c",&ch);
if(ch=='x')
ans++;
else
ans=0;
if(ans==3)
{
op++;
ans--;
}
}
printf("%d",op);
return 0;
}
CodeForce 855A
题目大意:给出一系列名字,判断后输入的是否先前已经出现
思路:直接使用unordered_map
代码
#include <iostream>
#include <cstring>
#include <unordered_map>
using namespace std;
unordered_map<string,bool>Names;
int n;
int main()
{
cin >>n;
while(n--)
{
string t;
cin >>t;
if(Names[t])
cout <<"YES";
else
cout <<"NO";
Names[t]=true;
cout <<endl;
}
return 0;
}
CodeForces 1384A
题目大意:给出一个数n,再给出n个数,分别代表编号1与2,2与3…n-1与n间的公共前缀的长度,输出满足条件的n个字符串,结果有很多,只需输出任意一种
思路:多种结果,那么假设初始字符串均为’a’,根据数字来决定哪一位不同就变哪一位,变完之后直接输出即可,本题用char数组会出错
代码
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;
int t;
int main()
{
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
string str(200,'a');
cout <<str<<endl;
while(n--)
{
int x;
scanf("%d",&x);
if(str[x]=='a')//如果初始为a则变为b,与原串在这一位不同,反之亦然
str[x]='b';
else
str[x]='a';
//str[x]=str[x]=='a'?'b':'a';
cout <<str<<endl;
}
}
return 0;
}
CodeForce 785A
题目大意:对应字符串有对应值,求和
思路:略
代码
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;
int ans[26]={0,0,6,12,0,0,0,0,20,0,0,0,0,0,8,0,0,0,0,4,0,0,0,0,0,0},N,sum;
int main()
{
scanf("%d",&N);
getchar();
while(N--)
{
char tmp[30];
scanf("%s",tmp);
getchar();
sum+=ans[tmp[0]-'A'];
}
printf("%d",sum);
return 0;
}
CodeForce 1473B
题目大意:定义最小公倍字符串,对于两个字符串,如果存在一个字符串可以由这两串复制自己构成,且该字符串在所有符合条件的串中长度最短,则这样的字符串为最小公倍字符串,现输入多组字符串,求其最小公倍字符串
思路:最小公倍字符串的长度必定小于等于两长度之积,因为如果最小公倍字符串存在,它的长度=A串重复单元个数×B串重复单元个数/个数的最大公因数,而重复单元个数一定小于等于本身长度,除以最大公因数后更是如此。又最小公倍字符一定是AB串中较小串长度的倍数,所以直接倍增较小串,判断在长度之积前倍增后的较小串能否“整除”较长串
代码
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
int Q,len,lena,lenb;
string a,b,tmp;
bool flag;
bool Judge()
{
if(len%lenb!=0) return false;
for(int i=0; i<len; i++)
if(tmp[i]!=b[i%lenb])
{
//cout <<tmp[i]<<" "<<b[i%lenb]<<endl;
return false;
}
return true;
}
int main()
{
scanf("%d",&Q);
while(Q--)
{
tmp="";
flag=false;
len=0;
cin >>a>>b;
if(a.size()>b.size())
swap(a,b);
lena=a.length(),lenb=b.length();
while(len<=lena*lenb)
{
tmp+=a;
//cout <<tmp<<endl;
len=tmp.length();
if((flag=Judge())==true)
break;
}
if(flag)
cout <<tmp<<endl;
else
cout <<"-1"<<endl;
}
return 0;
}
POJ 1035
题目大意:先输入多个字符串作为词典,再输入多个字符串作为查询的单词,如果单词属于字典,则输出正确信息,如果不属于,则判断修改一位或删除一位或插入一位是否能变成属于字典的单词,按照能构成单词的顺序输出
思路:模拟该过程即可,暴力枚举,为了确保输出顺序,将字典中的每一个单词与输入的单词进行长度比较,如果前者等于后者,尝试修改,刚好多1,尝试插入,刚好少1,尝试删除
代码
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef struct letter
{
int len;
char s[17];
} let;
let str[10017];
void Repl(char *s, char *ss)
{
int len = strlen(s),flag = 0,i = 0, j = 0;
while(i < len)
{
if(flag >= 2)
break;
if(s[i++] != ss[j++])
flag++;
}
if(flag < 2)
printf(" %s",s);
}
void Inse(char *s, char *ss)
{
int len = strlen(ss),flag = 0,i = 0, j = 0;
while(j < len)
{
if(flag >= 2)
break;
if(s[i] == ss[j++])
i++;
else
flag++;
}
if(flag < 2)
printf(" %s",s);
}
void Dele(char *s, char *ss)
{
int len = strlen(s),flag = 0,i = 0, j = 0;
while(i < len)
{
if(flag >= 2)
break;
if(s[i++] == ss[j])
j++;
else
flag++;
}
if(flag < 2)
printf(" %s",s);
}
int main()
{
char ss[17];
int k = 0;
while(scanf("%s",str[k].s)!=EOF)
{
str[k].len = strlen(str[k].s);
if(str[k].s[0]=='#')
break;
k++;
}
while(scanf("%s",ss)!=EOF)
{
if(ss[0] == '#')
break;
int len = strlen(ss),flag = 0;
for(int i = 0; i < k; i++)
{
if(!strcmp(ss,str[i].s))
{
printf("%s is correct\n",ss);
flag = 1;
break;
}
}
if(flag)
continue;
printf("%s:",ss);
for(int i = 0; i < k; i++)
{
if(len == str[i].len)
Repl(str[i].s,ss);
else if(len == str[i].len+1)
Inse(str[i].s,ss);
else if(len == str[i].len-1)
Dele(str[i].s,ss);
}
printf("\n");
}
return 0;
}
POJ 1936
题目大意:给出两个字符串,判断前者是否为后者缩写
思路:以第一个字符串为基准找到第二个字符串与其对应元素相等的位置,在此基础上继续延伸
代码
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
string s,t;
int main()
{
while(cin >>s>>t)
{
int lens=s.length(),lent=t.length(),pos=-1;
bool flag=false;
for(int i=0; i<lens; i++)
{
for(int j=pos+1; j<lent; j++)
{
if(s[i]==t[j])
{
flag=true;
pos=j;
break;
}
}
if(flag&&i!=lens-1)
{
flag=false;
continue;
}
else
break;
}
if(flag)
cout <<"Yes";
else
cout <<"No";
cout <<endl;
}
return 0;
}
POJ 2513
题目大意:给出多根木棒,头和尾各有自己的颜色,只有颜色相同一端才能相连,且每次只能两根木棒相连,现在判断所有木棒能否连成一条直线
思路:判断欧拉回路(通过图中每条边且只通过一次,并且经过每一顶点),将输入的各颜色看成图上的节点,将字符串使用字典树哈希获得对应的编号,利用编号+并查集来判断图是否连通,再记录每个点的度,判断度为奇数的点是否为0个或3个
代码
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;
int degree[500001],pre[500001],ans;
struct Trie
{
bool flag;
int id;
Trie*next[30];
Trie()
{
flag=false;
for(int i=0; i<30; i++)
next[i]=0;
}
} root;
int Hash(char*str)
{
int len=strlen(str);
Trie*t=&root;
for(int i=0; i<len; i++)
{
int id=str[i]-'a';
if(!t->next[id])
t->next[id]=new Trie();
t=t->next[id];
}
if(!t->flag)
{
t->flag=1;
t->id=ans++;
}
return t->id;
}
int Seek(int x)
{
if(pre[x]==x)return x;
return pre[x]=Seek(pre[x]);
}
void Union(int x,int y)
{
int fx=Seek(x),fy=Seek(y);
if(fx!=fy)
pre[fx]=fy;
}
int main()
{
char s[20],t[20];
for(int i=1; i<=500000; i++)
pre[i]=i;
while(~scanf("%s%s",s,t))
{
int x=Hash(s),y=Hash(t);
Union(x,y);
degree[x]++;
degree[y]++;
}
ans--;
int cnt=0,odd=0;
for(int i=1; i<=ans; i++)
{
if(degree[i]%2==1)
odd++;
if(pre[i]==i)
cnt++;
if(cnt>=2||odd>=3)
{
cout<<"Impossible"<<endl;
return 0;
}
}
cout<<"Possible"<<endl;
return 0;
}
POJ 3349
题目大意:给出多个雪花的6个角对应的角的个数,判断这些雪花中是否有顺时针看来相同或者逆时针看来相同的
思路:使用哈希的方法(求余)求取值,采用链地址法解决冲突,采用vector会超时,判断顺时针和逆时针相同分别判断A[i]==B[(i+j)%6](i为第i片雪花,j为B顺时针的偏移量)和A[i]==B[(5-i-j)%6]
代码
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
using namespace std;
int Prime = 999983,n,key;
int sum=0;
typedef struct node
{
int data[6],next;
} node;
node e[100100];
node x;
int hash[999984];//哈希只存储相等值的遍历到的最后一个元素,每个雪花保存自己的下一个相同值雪花
bool flag = false,judge;
int main()
{
scanf("%d",&n);
memset(hash,-1,sizeof(hash));
sum = 0;
while(n--)
{
key = 0;
for(int i=0; i<6; i++)
{
int t;
scanf("%d",&t);
key = ( key + t )%Prime;
x.data[i] = t;
}
if(!flag)//如果没找到
{
for(int i=hash[key]; i!=-1; i=e[i].next)
{
node t=e[i];
for(int j=0; j<6; j++)
{
judge = true;
for(int k=0; k<6; k++)
if(t.data[k]!=x.data[(5-j-k+6)%6])
{
judge=false;
break;
}
if( judge )
flag = judge;
}
for(int j=0; j<6; j++)
{
judge = true;
for(int k=0; k<6; k++)
if(t.data[k]!=x.data[(j+k)%6])
{
judge=false;
break;
}
if( judge )
flag = judge;
}
}
sum++;//记下雪花个数
e[ sum ] = x;//保存雪花数据
e[ sum ].next = hash[key];//雪花的下一个被赋值为哈希表对应的头,尾插入,参考链地址法的插入
hash[key] = sum;//当前雪花取代哈希链表头
}
}
if(flag)
cout<<"Twin snowflakes found."<<endl;
else
cout<<"No two snowflakes are alike."<<endl;
return 0;
}
POJ 2503
题目大意:给出两个字符串,前者为后者的翻译,这样的字符串有多组,输入多组作为词典,之后再输出多个字符串,输出其翻译,如果不存在输出对应信息
思路:因为没有给出确切的字符串组数,所以只能一行行读,然后进行分割,之后用map存储且查找即可,map的find函数效率高于[]符号
代码
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;
map<string,string>Dictionary;
map<string,string>::iterator p;
string output,input;
int main()
{
string line="";
while(1)
{
getline(cin,line);
if(line=="")break;
int pos=line.find(' ');
output=line.substr(0,pos);
input=line.substr(pos+1,line.rfind(' ')-pos-1);
Dictionary[input]=output;
}
char word[300];
while(scanf("%s",word)!=EOF)
{
if(Dictionary.find(word)!=Dictionary.end())
cout <<Dictionary[word];
else
printf("eh");
putchar('\n');
}
return 0;
}
总结
本周的题目较为基础,但是模拟赛的习题还是挺有难度,字符串部分需要整理好Weekly 5部分后加强练习