B题
签到题,题目问将给定的字符串重新排列成“Baidu”,其实就是判断给定的字符串是不是“Baidu”里的每一个字母都包含,这就需要满足两个条件:
1、字符串长度必须是5,因为“Baidu”长度为5.
2、字符串中的字母'B','a','i','d','u'必须都有,且仅有1个。
#include<stdio.h>
#include<string.h>
int main()
{
int t;scanf("%d",&t);
getchar();
while(t--)
{
int b=0,a=0,i=0,d=0,u=0;
char s[200010];
gets(s);
for(int j=0;j<strlen(s);j++)
{
if(s[j]=='B')b++;
else if(s[j]=='a')a++;
else if(s[j]=='i')i++;
else if(s[j]=='d')d++;
else if(s[j]=='u')u++;
}
if(strlen(s)==5&&b==1&&a==1&&i==1&&d==1&&u==1)printf("Yes\n");
else printf("No\n");
}
return 0;
}
D题
这道题乍一看很简单吧,相信有人看出要开long long,但一定会有人这样写吧?
#include<stdio.h>
int main()
{
long long a,b,n;
scanf("%lld%lld%lld",&a,&b,&n);
long long k=0;//天数
long long i=1;//模拟星期几
while(n>0)
{
if(i==6||i==7)
{
n-=b;
k++;
}
else
{
n-=a;
k++;
}
i++;
if(i==8)i=1;//如果由7加到8要变成星期一
}
printf("%lld",k);
return 0;
}
这样写是不是时间超限呢?没错!!!!!这次给你们普及一个知识,做题会给时间限制,一般都是1秒,而计算机1秒只能循环10^8左右,我们尽可能要控制在10^7以下,对于这题,我们假设最极限的数据,a=1,b=1,n=10^18,也就是每天只做一道题,像这样while一次循环也就是处理1天,那么我们做完10^18道题,也就是需要10^18天,也就是要循环10^18次,这样是不是已经超出10^8的时间限制了呢。
所以这道题我们要换一种思路,首先我们知道了周一到周五每天a题,周六周天每天b题,那么一星期的题目总数我们是不是可以算出来是a*5+b*2呢,我们先定义一个x记录做完这些题需要多少周(下取整),也就是x=n/(a*5+b*2),那么做完能整除7天题数的天数不就是x*7天啦?当然也可能除不尽,再定义一个y存最后不足一星期做的题数,y=n%(5*a+2*b),再通过循环求出剩余不足一周共y道题所用的天数k,最终结果就是x*7+k,下面上代码!
#include<stdio.h>
int main()
{
long long a,b,n;
scanf("%lld%lld%lld",&a,&b,&n);
long long x=n/(5*a+2*b),y=n%(5*a+2*b);
//x是用7天作为一个单位,x是几就代表做了 几周的题,那么天数是x*7
//y是不足七天的题目总数(最后一周剩余题目),(其中最后一周没有天天做题就已经完成任务)
long long k=0;
for(int i=1;i<=7;i++)//只需要循环7次,因为剩下y题是不足一周的题目总数
{
if(y<=0)break;//y<=0代表剩余题目已经做完
if(i==6||i==7)
{
y-=b;
k++;
}
else
{
y-=a;
k++;
}
}
printf("%lld",7*x+k);
return 0;
}
E题
题意:0~9的卡牌,每种有2023张,用来拼数字,看能拼到几。
我们可以直接用数组记录个数,从1开始枚举,去将每个数进行每一位的记录就行了,有2023直接break。
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[10];
signed main()
{
int f=0;
int k;
for(int i=1;;i++)
{
int x=i;
while(x)
{
int t=x%10;
a[t]++;
if(a[t]>2023)
{
k=i-1;//第i个数不能拼到,输出i-1
f=1;
break;
}
x/=10;
}
if(f==1)break;
}
cout<<k;
return 0;
}
G题
题意:把长度为n的子串每k个分为一段,求将每段变成相同的最小操作次数
例如 n=6,k=2 字符串为 abaaba
也就是分为 ab aa ba三段,不难看出将第一段的b跟第三段的b都换成a是最少操作次数(两次)。
题目懂了那我们就想想怎么做,第一个问题是我们怎样去计算最小操作次数
既然每一段的字母个数相同,那么我们可以一个位置一个位置的看呀,先看第一个位置在看第二个位置....一直到第k个位置,什么意思呢,看下图
样例n=6 k=2 也就是每段有2个字母,有n/k=3段
第一个位置
第一个位置有两个a一个b,那么我们至少要把第三段的b改成a,用了1次操作。
最多的字母个数是a有两次,那么需要操作n/k-2=1次
第二个位置
第二个位置有两个a一个b,那么我们至少要把第一段的b改成a用了1次操作
最多的字母个数是a有两次,那么需要操作n/k-2=1次
所以总共至少需要两次操作。
相信看到这里你已经懂了本题的做题思路,就是同一个位置不同段去统计字母个数,找到最多的字母次数,然后总段数减去这个次数,就是剩下最少要更改的字母(最小操作数)。
第二个问题来了,怎么记录次数???
我们可以先开一个长度为30的数组b,因为题目给了全部是小写字母,a~z总共26个应该都知道吧。。。所以开30个就足够。
然后我们去循环记录就行了,小tip:'a'-'a'=0,'b'-'a'=1,我们可以将每个位置减去'a'来记录abcd.....z的个数,其中0代表a,1代表b...25代表z。
#include<stdio.h>
int main()
{
int n,k;
scanf("%d%d",&n,&k);
char a[n+10];
scanf("%s",a);
int cnt=0;
for(int i=0;i<k;i++)//每段有k个字母
{
int b[30]={0};//记录每个小写字母的个数
for(int j=0;j<n/k;j++)//n/k就是有多少段
{
b[a[j*k+i]-'a']++; //将每段的第i个字母记录下来
// a[j*k+i]代表第j段第i个字母
//例如样例 ab aa ba j=0,i=0
//也就是a[0*2+0] a[0] 就是第一段ab中的a
// j=1,i=0 a[1*2+0] a[2]也就是第二段aa中的第一个a
}
int res=0;//求出一段中每个位置字母出现最多的个数
for(int j=0;j<26;j++)
{
if(res<b[j])res=b[j];
}
cnt+=n/k-res;//n/k-res就是当前位置最少需要更改几段(几次)
//例如样例 ab aa ba n=6,k=2
//第一次循环是看 (a)b (a)a (b)a中括号中最少需要更改第三段的b
//第二次循环是看 a(b) a(a) b(a)中括号最少需要更改第一段的b
}
printf("%d",cnt);
return 0;
}