话不多说,直接进入正题!
E、苹果采购:
题目大意:
给n个同学每个同学a个苹果,已知n个a,问至少要多少个苹果才够。
题解:
这题属签到题,非常简单,也没有卡int数据范围,只是要注意一下多组输入的问题就可以了。
#include <stdio.h>
int main()
{
int n, m;
while(~scanf("%d%d", &n, &m))
printf("%d\n", n*m);
return 0;
}
G、迟到的猴子
题目大意:
一共有100只猴子,每个猴子都有自己的编号1-100,其中只有n只猴子到场了,问 没到场的猴子中编号最小的是几号。
题解:
因为每个猴子的编号是唯一的,所以我们只需要开一个110的数组a[110],使其初始值为0,在输入到场的猴子的编号,设第 i 只猴子的编号是xx, 则令a[xx] = 1,最后将编号从1枚举到100, 若a[i] == 0,则说明这只猴子没到场,输出该编号 i 即可。
#include <stdio.h>
int n, a[110] = {0};
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
{
int xx; scanf("%d", &xx);
a[xx] = 1;
}
for(int i = 1; i <= 100; i ++)
if(a[i] == 0)
{
printf("%d\n",i);
break;
}
return 0;
}
A、选举
题目大意:
有三个人参加选举,分别是a,b,c票;问 这三个人各自至少要再得多少票才能使自己的票数变得最高。
题解:
首先用一个数组将三个人的得票存起来,再建一个数组存答案;用两重循环将每两两相差的票算出来,记录两两相差中最大的差距。(注意:当两重循环两两比较遇到同一个人时,可以直接跳)
#include <stdio.h>
int main()
{
int a[3], ans[3];
while (~scanf("%d%d%d", a, a + 1, a + 2))
{
ans[0] = ans[1] = ans [2] = 0;
for (int i = 0; i < 3; i ++)
for (int j = 0; j < 3; j ++)
{
if(i == j) continue;
if(a[j] - a[i] >= ans[i]) ans[i] = a[j] - a[i] + 1;
}
printf("%d %d %d\n", ans[0], ans[1], ans[2]);
}
return 0;
}
B、吃羊问题
题目大意:
岛上有若干只虎和一只羊,所有老虎都想吃羊,但是吃了羊之后自己就会变成羊,当然老虎也可以选择吃草,问 当岛上有n只虎时,羊会不会被吃,会就输出Yes,不会则输出No
题解:
典型的逻辑思维题,可以很明确的说 当n为偶数时,羊不会被吃,当n为奇数时,羊就会被吃;
为什么?先模拟一遍,只有一只虎时,那他可以毫不犹豫的选择把羊吃了;当虎变成两只时,他们俩都不敢妄动,因为只要其中一只吃了羊,就会变成羊,另一只也会毫不犹豫把它吃了,以此类推,三四五只羊都是这样的,所以这就转变成了一个关于奇偶的问题。(注意:n的数据范围是[1, 1e18), 所以n的数据类型要开long long);
#include <stdio.h>
int main()
{
long long n;
while(~scanf("%lld", &n))
if(n % 2) puts("YES");
else puts("NO");
return 0;
}
C、教练,我要打ACM
题目大意:
在桌子上有n颗瓜子,XX老师和DD老师可以一次拿1-3颗,谁拿到最后一颗瓜子谁就获胜,DD老师先拿,问 在两人都足够聪明的情况下 谁更可能获胜。
题解:
巴什博弈 在两人都足够聪明的情况下,结局是固定的。
#include <stdio.h>
int n;
int main()
{
int n;
while(~scanf("%d", &n))
if(n%4 == 0) puts("XX");
else puts("DD");
return 0;
}
D、甜甜圈
题目大意:
给定首尾相接的n个数,有 t 个问题,每个问题有两个参数 i , j;问 该数组中[i, j]的和是多少。
题解:
首先我们先建一个数组ans,令ans[i]为原始a数组中前 i 个数的和,那么对于每个问题的参数。
可得:ans[j] = a[1] + a[2] + ...... + a[i] + a[i + 1] + ...... + a[j – 1] + a[j];
但是我们只需要知道 a[i] + a[i + 1] + a[i + 2] + ...... + a[j – 1] + a[j];
同理我们可知:ans[i – 1] = a[1] + a[2] + a[3] + ...... + a[i - 2] + a[i – 1];
所以我们可以得出 对于原始a数组中[i, j] 的和为ans[ j ] – ans[ i – 1];
但是这个公式只对于i < j的时候,那当i > j的时候呢?
题目所述,该数组是首尾相接的,则当i > j 时,我们的答案应该是
a[i] + a[i + 1] + a[i + 2] + ...... + a[n] + a[1] + a[2] + ...... + a[j - 1] + a[j];
由我们对ans的定义可知道:ans[n] = a[1] + a[2] + a[3] + a[4] + ...... + a[n – 1] + a[n];
对于ans[n] 我们只需要减去多加的部分可以了,因为j < i 所以我们可知多加的部分为:
a[j + 1] + a[j + 2] + a[j + 3] + ...... + a[i – 2] + a[i - 1] = ans [i – 1] – ans[j];
则当 i > j 时,其结果为:ans[n] - ans[i – 1] + ans[j];
我们只需要判断 i 和 j 的大小情况输出相应的公式即可
(这题可以暴力 但不建议,因为这里只是数据弱,对于强一点的数据很容易超时)
#include <stdio.h>
int n, m;
int a[10010];
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
{
scanf("%d", a + i);
a[i] += a[i - 1];
}
scanf("%d", &m);
while (m --)
{
int x, y; scanf("%d%d", &x, &y);
if(x <= y)
printf("%d\n", a[y] - a[x-1]);
else printf("%d\n", a[n] - a[x-1] + a[y]);
}
return 0;
}
F、特别的数组
题目大意:
给定一个大小为n的数组,你可以在数组最后添加一个非负数,使该数组的平均值等于1,问 最少添加几个数才能使其数组平均值变为1。
题解:
首先令sum为给定数组的和,则由题可分类为:sum == n、sum > n、sum < n;
很显然当sum == n时,sum / n == 1;所以这种情况只需要输出0即可。
当sum > n时,sum / n必然大于1,要是sum / n变小,我们需要将被除数变小,除数变大;但是由题可知,我们所添加的数只能是非负数,所以我们无法将sum变小,只能在sum保持不变的情况下将n变大,则我们只需要在数组最后添加sum - n个0即可,所以答案为sum – n。
当sum < n就更简单了,我们只需要令sum == n,所以我们在数组后面添加一个数 n – sum,则操作数为 1,答案为 1。
#include <stdio.h>
int n, a[1010], ans;
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
{
scanf("%d", a + i);
ans += a[i];
}
if(ans == n) ans = 0;
else if(ans > n) ans = ans - n;
else ans = 1;
printf("%d\n", ans);
return 0;
}
H、对角线
题目大意:
对于一个有n个顶点的凸多边形,求其对角线交点的个数。
题解
首先分析一下交点个数怎么求。一个四边形,交点只有一个,也就是,四个顶点,确定一个交点,所以边少于4的图形都没有对角线,更别谈交点了。那么n边形(n>=4),也就是从n个顶点里面选取四个,且没有顺序,所以顶点个数就是4Cn,既得到公式
ans = n * (n-1) * (n-2) * (n-3)/(4 * 3 * 2 * 1)
#include <stdio.h>
int main()
{
long long n;
while(~scanf("%lld",&n))
printf("%lld\n", n * (n - 1) / 2 * (n - 2) / 3 * (n - 3) / 4);
return 0;
}
I、进制转换
题目大意:
将一个八进制数字转换成十六进制,不输出前导0。
题解:
单纯的模拟题,直接模拟一遍就可以了,只是要注意时间复杂度不要超时
(但是数据可能没那么强,一般的模拟也不会超)
#include <stdio.h>
#include <string.h>
#define N 10010
#define M 30010
int a[4] = {1, 2, 4, 8};
char st[10][5] = {"000", "001", "010", "011", "100", "101", "110", "111"};
// 代码预处理
int main()
{
int t = 1; scanf("%d", &t);
while (t --)
{
char ans[N], base_8[N], base_2[M] = {'\0'}; // 对base_2数组清空;
scanf("%s", base_8);
for(int i = 0; i < strlen(base_8); i ++) // 遍历base_8数组中每一个字符并依次转换为二进制
{
int xx = base_8[i] - '0';
strcat(base_2, st[xx]);
}
int idx = -1, pos = 0;
for(int i = strlen(base_2) - 1, j = 0; ~i; i --)
{
if(base_2[i] == '1') pos += a[j];
j ++;
if(j == 4 || i == 0) // 四位二进制转一位十六,集齐就转;或者当二进制不够了也转;
{
if(pos < 10) ans[++ idx] = '0' + pos;
else ans[++ idx] = 'A' + pos - 10;
j = pos = 0;
}
} // 二转十六进制
int flag = 1;
for(int i = idx; ~i; i --) // 因为二转十六的时候,是从低位开始转的,但是放在ans数组中变成了高位
if(ans[i] == '0' && flag) continue; // 所以需要从后往前输出,高位中的0不输出
else {
putchar(ans[i]);
flag = 0;
}
puts("");
}
return 0;
}
最后小编想说:
对于这次比赛没有做出题目的同学,并不代表什么。不过是有一部分同学提前学习过而已,后续还会有更多的比赛;
我相信会有同学能实现弯道超车,ACM协会是一个技术互助的社团,目的是鼓励大家相互学习。大家可以一起讨论,继续参与后续比赛复盘和新的比赛。