每日一题题解汇总(不定时更新)

第一次写题解,以下题解均仅供参考,如果有误,欢迎指正!

目录

10.9 国际裁判带师

10.10 优美的GCD

10.11 猫猫与密信 

 10.12 魔导师晨拥

10.16 中位数

10.17 Kevin喜欢一

10.18 红包


10.9 国际裁判带师

  题目链接

题目描述

示例

输入

aab

输出

8

说明

第一次红方得分,计分表变成 `0001`,出现了 3 个 0。

第二次红方得分,计分表变成 `0002`,出现了 3 个 0。

第一次蓝方得分,计分表变成 `0102`,出现了 2 个 0。

总计出现了 8 次数字 0。 

 解题思路

从左到右扫描字符串,字符为“a”,则红方计分,字符为“b”,则蓝方计分,每计分一次则记录有几个0。

纯纯暴力,无算法!

用两个变量记录红蓝双方当前得分情况

记录有几个0有如下3种情况:

1.个位为0十位不为0  如:01   1个0

2. 十位、个位都为0   如:00   2个0

3. 十位不为0个位为0 如:10   1个0

则可以用三个if…else语句来判断,符合则计数有几个0

代码实现如下

#include <stdio.h>
#include <string.h>
char s[110];

int main()
{
    int l=0,h=0;//l记录当前蓝方得分,h记录当前红方得分
    int ans = 0;//ans记录最终答案
    scanf("%s",s);//输入字符串
    for(int i=0;i<strlen(s);i++)//注意使用strlen函数来统计字符串长度时要调用string.h头文件
    {
        if(s[i] == 'a')  h ++; 
        else if(s[i] == 'b') l ++;
        
        //注意了,为00的情况要先考虑,不然会进入0%10 == 0的判断
        if(h == 0) ans += 2;
        else if(h%10 == 0 || h>=1 && h<=9) ans ++;
        
        if(l == 0) ans += 2;
        else if(l%10 == 0 || l>=1 && l<=9) ans ++;
    }
    printf("%d",ans);
}

10.10 优美的GCD

题目链接

题目描述
 

样例不放了 

解题思路

水题,大水题!!

求最大公约数为n的两个数x,y,只需输出任意一组

不要考虑复杂情况,我们只要输出任意一组符合的就行

则可以想到 n与2*n的最大公约数为n,因为n的最大约数为本身,不可能超过这个,同时也必然是2*n的约数,则符合题意

代码实现如下

#include <stdio.h>

int main()
{
    int t;
    scanf("%d",&t);//t组数据,每组一个n
    while(t--)
    {
        int n;
        scanf("%d",&n);
        printf("%d %d\n",n,n*2);
    }
}

10.11 猫猫与密信 

 题目链接

 题目描述

样例也懒得放了

解题思路

就是在一串字符里查找如下几种情况:

love

lov

lve

loe

ove

介绍一个c语言好用的截取字串的函数 strstr ,此篇末放链接

好了,暴力解题就行

代码实现如下:

#include <stdio.h>
#include <string.h>
#define M 100010
char s[M];

int main()
{
    gets(s);
    if(strstr(s,"love") || strstr(s,"lov") || strstr(s,"lve") || strstr(s,"loe") || strstr(s,"ove"))
    {
        printf("YES");
    }
    else
    {
        printf("NO");
    }
}

 strstr使用


 10.12 魔导师晨拥

 题目链接

题目描述

示例

输入

5 6
1 2 3 4 5

 输出

36

 说明

初始英雄技能伤害为 2。

第一次战吼:先攻击血量为 1 的随从,由于不是恰好消灭,英雄技能伤害不增加,再攻击血量为 2 的随从,恰好消灭,英雄技能伤害增加到 3,再攻击血量为 3 的随从,恰好消灭,英雄技能伤害变为 4,以此类推,攻击完所有随从后的英雄技能伤害为 6,打一次敌方英雄造成 6点伤害。

之后的 5 次战吼由于随从全部死亡,所以直接攻击敌方英雄,都造成 6 点伤害,故而对敌方英雄造成的总伤害为 6×6=36(第一次战吼造成了 6点伤害,随后 5 次都造成 6 点伤害)

解题思路

暴力!!

遍历m次,如果当前的随从恰好被打死,则伤害永久+1,当然只有当前的随从仍活着才要减去伤害,然后在每次遍历后加上当前的最终伤害。

代码实现如下: 

#include <stdio.h>
int a[10];

int main()
{
    int n,m,ans=0,sum=2; // ans记录最终对敌方英雄造成的伤害,sum为当前的伤害值
    scanf("%d %d",&n,&m);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]); //输入随从血量
    }
    while(m--) //遍历m次
    {
        for(int i=0;i<n;i++)//每次遍历随从
        {
            if(a[i]) //如果随从还活着
            {
                a[i] -= sum; //减去伤害
                if(a[i]==0) sum++; //如果随从恰好被打死,伤害永久加1
            }
        }
        ans += sum; //每次遍历结尾统计对敌方英雄的伤害
    }
    printf("%d",ans);
}

10.16 中位数

题目链接

题目描述

输入样例

1
5 1
4 3 5 1 2

输出

 解题思路

贪心(可以这么说吧)

中位数即按顺序居于中间的数,用mid来指代
在一个升序的数组中,合并两项,mid会前移,所以要使mid的值最小,那么就要尽量合并当前最大的两个数,因为合并较小的数会使数值增大,则mid指向的数可能会较大。
如:
一个升序数组:1,2,3,4,5
合并2次
第一次合并:

合并最大两个数:1,2,3,9     mid 值为2

合并最小两个数:3,3,4,5     mid 值为3
第二次合并:

合并最大两个数:1,2,12         mid 值为2
合并最小两个数:4,5,9           mid值为 5

综上所述,即是不断的合并当前的最大两个数,使mid前移,指向更小的数,代码实现如下

#include <stdio.h>
typedef long long ll;
#define M  200010
ll a[M],t[M];

//归并板子,不懂的自行查找相关资料学习
void merge_sort(int l,int r)
{
    if(l>=r) return ;
    int mid = l+r >> 1;
    merge_sort(l,mid),merge_sort(mid+1,r);
    int k=0,i=l,j=mid+1;
    while(i<=mid && j<=r)
    {
        if(a[i]<=a[j]) t[k++] = a[i++];
        else t[k++] = a[j++];
    }
    while(i<=mid) t[k++] = a[i++];
    while(j<=r) t[k++] = a[j++];
    for(int i=l,j=0;i<=r;j++,i++) a[i] = t[j];
}

int main()
{
    int t;//t组数据
    scanf("%d",&t);
    while(t--)
    {
        int n,k;
        scanf("%d %d",&n,&k);//数组长度为n,合并次数为k
        for(int i=0;i<n;i++) scanf("%lld",&a[i]);//输入数据
        //用归并排序时间复杂度为O(nlogn)
        merge_sort(0,n-1);
        //c++选手直接使用sort函数排序
        //合并操作,从后面扫描,让两个数相加并赋给更新后的结尾
        for(int i=n-1;i>n-1-k;i--) a[i-1] += a[i];
        //输出最新数组的中位数,注意数组的长度
        printf("%lld\n",a[(n-1-k)/2]);
    }
}

关于为什么使用归并排序
看题目给出的数据范围,2<=n<=200000,即数组最长可能是2e5
如果使用冒泡、选择,时间复杂度是O(n^2),即是4e10
一般比赛 限制时间1秒,可以运行1e8的量级
所以使用常规的排序可能会出现超时现象


10.17 Kevin喜欢一

题目链接 

题目描述

 示例

输入

2
1
2

输出

0
1

解题思路

贪心

初始有一个1,要最快到达n个1,那么就贪心的让自己的数量扩大一倍增长(*2),因为可以任意复制部分的字符,所以最后一次操作n - now可以用*2代替

如: 目标数n为9

1                               1个

11                              2个

1111                          4个

11111111                   8个

1111111111111111     16个

最后一次操作超过了目标数,但本次的操作是需要的,只不过不是*2,而是+1,我们可以任意复制粘贴部分字符,最后一次的操作可以灵活修改。(解释的不是很好,认真理解一下)

代码实现如下:

#include <stdio.h>
int main()
{
    int t;
    scanf("%d",&t);//t组数据
    while(t--)
    {
        int n,ans=0,num=1; // ans记录操作次数,num为当前1的数量
        scanf("%d",&n);
        while(num < n) //但1的数量超过目标时可以退出
        {
            num *= 2;
            ans ++;
        }
        printf("%d\n",ans);
    }
}

10.18 红包

题目链接

题目描述

 示例

输入

4
1X5
125
X
20

输出

1

输入

4
125
1X5
X
20

输出

2

 解题思路

字符串 + 贪心

题目不难理解,就是拿可能最大的红包

那么最大红包的可能性有如下几种:

1. 数字长度最大的也就是最大的,如100 比 99 大(没有前导0影响)

2. 数字长度一样,但X位置较前,因为我们可以让X 的大小比其他长度一样的数字更大

那么要拿尽可能的大的红包,也就是X要尽可能的大,就可以贪心的让X就等于9,这样我们就可以方便比较两个数谁更大了。

代码实现:

#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define M 1200
char s[M],ans[M];
//改变'X' 为 '9'
void change(char a[])
{
    for(int i=0;i<strlen(a);i++)
    {
        if(a[i] == 'X') a[i] = '9';
    }
}
//比较函数
bool cmp(char a[],char b[]) // c语言 bool变量要用头文件 stdbool.h
{
    if(strlen(a) != strlen(b)) return strlen(a) > strlen(b); // 如果两个字符串的长度不一样,那么取长度大
    else return strcmp(s,ans) > 0; // 如果一样,那么比较两个字符串,介绍c语言比较两字符串的函数strcmp
}
int main()
{
    int n,sel=1;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s); 
        change(s); // 'X' -> '9'
        if(cmp(s,ans)) //符合条件s > ans,则ans 变为 s
        {
            strcpy(ans,s); //介绍 c语言的字符串复制函数 strcpy
            sel = i; //注意标记是第几个红包
        }
    }
    printf("%d",sel);
}

 特别说明

为什么要用字符数组

注意题目给出的数据范围1~10^100,这是1000000000.......0000(一百个0),这么大的数在c语言中能表示最大的整型数据类型long long 仅能表示-2^63 ~ 2^63-1 也就是1e18级,远低于题目范围,此时我们就要用字符数组来表示一组数,毕竟你100位的数字表示成数组也就是100个字符。

代码中的两个字符串函数 strcmp和strcpy 自行查找资料学习,课本上也有。


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值