pdsuACM第七次招新赛BDEG

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;
}

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值