第一次写题解,以下题解均仅供参考,如果有误,欢迎指正!
目录
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");
}
}
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
输出
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 自行查找资料学习,课本上也有。