题目描述(已转换成中文)
还记得2020年招新赛中“编织字符串”这一道题吗?
tls在ac完以后想出了一个更有趣的问题,具体是这样的:给定两个长度均为len的字符串s1、s2和一个长度为len2的字符串s,每一次我们按照编织字符串的操作将s1和s2拼接起来(注意这里s2先拼接,具体请看样例),得到长度为len2的字符串s’,然后令s1为s’的前一半,s2为s’的后一半,反复以上操作。若在某一次中s’和s相等则结束循环。
假设有s1=“JNU”,s2=“ACM”,s=“NAMJUC”,第一次操作后得到s’=“AJCNMU”,与s不相等。令s1=“AJC”,s2=“NMU”,第二次操作后得到s’=“NAMJUC”,与s相等,结束循环。输出操作次数为2。
输入格式
第一行一个整数T(1≤T≤1000),代表测试数据组个数。
对于每组数据,第一行为len(1≤len≤100),第二行为字符串s1,第三行为字符串s2,第四行为字符串s。
输入保证s1和s2长度均为len,s长度为len*2
输出格式
对每一组数据,输出数据组编号和答案。如果无论经过多少次操作也无法结束循环,答案输出-1。
输入输出样例
输入
2
3
JNU
ACM
NAMJUC
3
JNU
ACM
ACMJNU
输出
1 2
2 -1
题目链接
分析:
这道题是对字符串进行处理,问能不能得到目标字符串,并输出得到目标字符串所需的操作次数。不断循环分割字符串,再拼接,如果遇到字符串(不是目标字符串的)是之前出现过的,则之后会陷入循环,永远得不到目标字符串,输出-1.
这道题需要注意的地方:
要用map <string, int> q来记录某个字符串是否之前出现过,q[s] == 1即代表字符串s之前出现过一次,这种关联函数很好用。
代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
using namespace std;
typedef long long LL;
char a[105], b[105], c[210], s[210];
int read(){
int x, f = 1;
char ch;
while(ch = getchar(), ch < '0' || ch > '9') if(ch == '-') f = -1;
x = ch - '0';
while(ch = getchar(), ch >= '0' && ch <= '9') x = x * 10 + ch - 48;
return x * f;
}
int main(){
int i, j, ans, sum, l, p, t = read();
for(j = 1; j <= t; j++){
p = 0; //标记在得到目标字符串的过程中,某个字符串是否出现过两次
ans = 0; //标记操作的次数
l = read();
scanf("%s", a); //输入s1
scanf("%s", b); //输入s2
scanf("%s", c); //输入目标字符串
map<string, int> q; //用map来记录字符串是否出现过
while(1){
ans++; //记录操作的次数
sum = 0; //记录字符串的位数
for(i = 0; i < l; i++){
s[sum++] = b[i]; //s2先拼凑
s[sum++] = a[i];
}
s[sum] = '\0'; //终止字符串的拼凑
if(strcmp(s, c) == 0) break; //字符串已经跟目标字符串相同
if(q[s] == 1){ //如果之前出现过这个字符串
p = 1; //接下来会是循环操作,永远得不到目标字符串
break;
}
q[s] = 1; //标记这个字符串出现过
for(i = 0; i < l; i++){ //把字符串分割成前后两半
a[i] = s[i];
b[i] = s[i + l];
}
a[i] = b[i] = '\0';
}
printf("%d ", j);
if(!p) printf("%d\n", ans); //输出得到目标字符串所需的操作次数
else printf("-1\n");
}
return 0;
}