目录
一、字符串移位包含问题
对于一个字符串来说,定义一次循环移位操作为:将字符串的第一个字符移动到末尾形成新的字符串。
给定两个字符串 s1 和 s2,要求判定其中一个字符串是否是另一字符串通过若干次循环移位后的新字符串的子串。
例如 CDAA
是由 AABCD
两次移位后产生的新串 BCDAA
的子串,而 ABCD
与 ACBD
则不能通过多次移位来得到其中一个字符串是新串的子串。
输入格式
共一行,包含两个字符串,中间由单个空格隔开。
字符串只包含字母和数字,长度不超过 30。
输出格式
如果一个字符串是另一字符串通过若干次循环移位产生的新串的子串,则输出 true
,否则输出 false
。
输入样例:
AABCD CDAA
输出样例:
true
#include<iostream>
#include<algorithm> //含有swap函数
using namespace std;
int main(){
string a,b;
cin>>a>>b;
if(a.size()<b.size()) swap(a,b);
for(int i=0; i<a.size(); i++)
{
a=a.substr(1)+ a[0]; //先通过substr把a的第0个位置去掉,再在后面加上a[0]
for(int j=0; j+b.size()<=a.size(); j++) //接下来枚举b是否是a的子串
{
for(int k=0; k<b.size(); k++) //用k来遍历是不是所有的位置都相等
{
if(a[j+k]!=b[k])
{
break;
}
if(k == b.size())
{
puts("true");
return 0;
}
}
}
}
puts("false");
return 0;
}
二、孤独的照片
Farmer John 最近购入了 N 头新的奶牛,每头奶牛的品种是更赛牛(Guernsey)或荷斯坦牛(Holstein)之一。
奶牛目前排成一排,Farmer John 想要为每个连续不少于三头奶牛的序列拍摄一张照片。
然而,他不想拍摄这样的照片,其中只有一头牛的品种是更赛牛,或者只有一头牛的品种是荷斯坦牛——他认为这头奇特的牛会感到孤立和不自然。
在为每个连续不少于三头奶牛的序列拍摄了一张照片后,他把所有「孤独的」照片,即其中只有一头更赛牛或荷斯坦奶牛的照片,都扔掉了。
给定奶牛的排列方式,请帮助 Farmer John 求出他会扔掉多少张孤独的照片。
如果两张照片以不同位置的奶牛开始或结束,则认为它们是不同的。
输入格式
输入的第一行包含 N。
输入的第二行包含一个长为 N 的字符串。如果队伍中的第 i 头奶牛是更赛牛,则字符串的第 i 个字符为 G
。否则,第 i 头奶牛是荷斯坦牛,该字符为 H
。
输出格式
输出 Farmer John 会扔掉的孤独的照片数量。
数据范围
3≤N≤5×10的五次方
输入样例:
5
GHGHG
输出样例:
3
样例解释
这个例子中的每一个长为 3 的子串均恰好包含一头更赛牛或荷斯坦牛——所以这些子串表示孤独的照片,并会被 Farmer John 扔掉。
所有更长的子串(GHGH
、HGHG
和 GHGHG
)都可以被接受。
解析:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 500010;
int n;
char str[N];
int l[N], r[N];
int main()
{
scanf("%d", &n);
scanf("%s", str);
for (int i = 0, h = 0, g = 0; i < n; i ++ )
if (str[i] == 'G') l[i] = h, h = 0, g ++ ;
else l[i] = g, g = 0, h ++ ;
for (int i = n - 1, h = 0, g = 0; i >= 0; i -- )
if (str[i] == 'G') r[i] = h, h = 0, g ++ ;
else r[i] = g, g = 0, h ++ ;
LL res = 0;
for (int i = 0; i < n; i ++ )
res += (LL)l[i] * r[i] + max(l[i] - 1, 0) + max(r[i] - 1, 0);
printf("%lld\n", res);
return 0;
}
三、 统计次数
给定两个正整数 n 和 k,求从 1 到 n 这 n个正整数的十进制表示中 k 出现的次数。
输入格式
共一行,包含两个整数 n 和 k。
输出格式
输出一个整数,表示答案。
数据范围
1≤n≤10的6次方
1≤k≤9
输入样例:
12 1
输出样例:
5
样例解释
从 1到 12 这些整数中包含 1 的数字有 1,10,11,12一共出现了 5 次 1。
解析:
#include<iostream>
using namespace std;
int main(){
int n,k;
cin>>n>>k;
int res=0; //res为结果
for(int i=1; i<=n; i++)
{
int s=i;
while(s>0)
{
if(s%10 == k)
{
res++;
}
s/=10;
}
}
cout<<res;
return 0;
}
四、上课睡觉
有 N 堆石子,每堆的石子数量分别为 a1,a2,…,aN
你可以对石子堆进行合并操作,将两个相邻的石子堆合并为一个石子堆,例如,如果 a=[1,2,3,4,5],合并第 2,3 堆石子,则石子堆集合变为 a=[1,5,4,5]。
我们希望通过尽可能少的操作,使得石子堆集合中的每堆石子的数量都相同。
请你输出所需的最少操作次数。
本题一定有解,因为可以将所有石子堆合并为一堆。
输入格式
第一行包含整数 T,表示共有 T 组测试数据。
每组数据第一行包含整数 N。
第二行包含 N 个整数 a1,a2,…,aN
输出格式
每组数据输出一行结果。
输入样例:
3
6
1 2 3 1 1 1
3
2 2 3
5
0 0 0 0 0
输出样例:
3
2
0
样例解释
第一组数据,只需要用 3 个操作来完成:
1 2 3 1 1 1
-> 3 3 1 1 1
-> 3 3 2 1
-> 3 3 3
第二组数据,只需要用 2 个操作来完成:
2 2 3
-> 2 5
-> 7
第三组数据,我们什么都不需要做。
解析:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
int n; //每组有n堆
int w[N]; //每堆的石子数量
//判断一个堆数能否成立
bool check(int cnt) //cnt是每段的石子个数
{
for(int i=0,s=0; i<n; i++) //枚举每一段
{
s+=w[i];
if(s>cnt) return false;
if(s==cnt) s=0;
}
//所有段的cnt都满足
return true;
}
int main(){
int T;
cin>>T;
while(T--)
{
cin>>n;
int sum=0; //这一序列的总和
for(int i=0;i<n;i++)
{
cin>>w[i];
sum += w[i];
}
//枚举一下堆数,堆数越多,操作次数就越少
for(int i=n; i>0; i--)
{
if(sum%i==0 && check(sum/i)) //堆数也是总和的约数
//i是堆数,sum/i是每堆的石子数量
{
cout<<n-i<<endl;;
break;
}
}
}
return 0;
}