3.31实验室二面题题解
小车问题
题目描述
甲、乙两人同时从 A 地出发要尽快同时赶到 B 地。出发时 A 地有一辆小车,可是这辆小车除了驾驶员外只能带一人。已知甲、乙两人的步行速度一样,且小于车的速度。问:怎样利用小车才能使两人尽快同时到达。
输入格式
仅一行,三个实数,分别表示 AB 两地的距离 s s s,人的步行速度 a a a,车的速度 b b b。
输出格式
两人同时到达 B 地需要的最短时间,保留 6 6 6 位小数。
样例 #1
样例输入 #1
120 5 25
样例输出 #1
9.600000
提示
数据规模与约定
对于 100 % 100\% 100% 的数据,保证 0 ≤ s , a , b ≤ 1 0 9 0 \leq s, a, b \leq 10^9 0≤s,a,b≤109。
考察知识点
小学奥数题
解题思路
- 求解两人同时达到的最短时间,先让甲步行,乙先乘车前进,而后小车折返回来接甲,最后同时到达终点。
- 当车行走 x x x米后将乙放下,而后返回来接甲,则这段距离时间即为 2 ∗ x / ( n + m ) 2*x/(n + m) 2∗x/(n+m) 而后甲乘车,乙步行,两人同时到达终点。
- 这段时间也是乙步行至终点的时间,即 ( s − x ) / n (s-x)/n (s−x)/n。
- 结合两个式子即可求出 x = ( 2 ∗ n ∗ s ) / ( m + 3 ∗ n ) x=(2 * n * s)/(m+3*n) x=(2∗n∗s)/(m+3∗n) ,最后即可得到结果。
代码实现
#include <stdio.h>
int main() {
double s, n, m;
scanf("%lf %lf %lf", &s, &n, &m);//使用双精度浮点型记录数据,便于运算
double x = 0;
x = (2 * n * s) / (m + 3 * n);
double sum = x / n + (s - x) / m;
printf("%.6lf", sum);
return 0;
}
[NOIP2008 提高组] 笨小猴
题目链接:[NOIP2008 提高组] 笨小猴
题目描述
笨小猴的词汇量很小,所以每次做英语选择题的时候都很头疼。但是他找到了一种方法,经试验证明,用这种方法去选择选项的时候选对的几率非常大!
这种方法的具体描述如下:假设 maxn \text{maxn} maxn 是单词中出现次数最多的字母的出现次数, minn \text{minn} minn 是单词中出现次数最少的字母的出现次数,如果 maxn − minn \text{maxn}-\text{minn} maxn−minn 是一个质数,那么笨小猴就认为这是个 Lucky Word,这样的单词很可能就是正确的答案。
输入格式
一个单词,其中只可能出现小写字母,并且长度小于 100 100 100。
输出格式
共两行,第一行是一个字符串,假设输入的的单词是 Lucky Word,那么输出 Lucky Word
,否则输出 No Answer
;
第二行是一个整数,如果输入单词是 Lucky Word
,输出
maxn
−
minn
\text{maxn}-\text{minn}
maxn−minn 的值,否则输出
0
0
0。
样例 #1
样例输入 #1
error
样例输出 #1
Lucky Word
2
样例 #2
样例输入 #2
olympic
样例输出 #2
No Answer
0
提示
【输入输出样例 1 解释】
单词 error
中出现最多的字母
r
\texttt r
r 出现了
3
3
3 次,出现次数最少的字母出现了
1
1
1 次,
3
−
1
=
2
3-1=2
3−1=2,
2
2
2 是质数。
【输入输出样例 2 解释】
单词 olympic
中出现最多的字母
i
\texttt i
i 出现了
1
1
1 次,出现次数最少的字母出现了
1
1
1 次,
1
−
1
=
0
1-1=0
1−1=0,
0
0
0 不是质数。
(本处原题面错误已经修正)
noip2008 提高第一题
提示
【输入输出样例 1 解释】
单词 error
中出现最多的字母
r
\texttt r
r 出现了
3
3
3 次,出现次数最少的字母出现了
1
1
1 次,
3
−
1
=
2
3-1=2
3−1=2,
2
2
2 是质数。
【输入输出样例 2 解释】
单词 olympic
中出现最多的字母
i
\texttt i
i 出现了
1
1
1 次,出现次数最少的字母出现了
1
1
1 次,
1
−
1
=
0
1-1=0
1−1=0,
0
0
0 不是质数。
(本处原题面错误已经修正)
noip2008 提高第一题
考察知识点
质数,哈希表
解题思路
- 这道题是一个简单的哈希表,故而先创建一个整型数组用于存放每个字母出现的次数。
- 再遍历该整型数组,找到出现字母的最大值,最小值,作差。
- 最后将差值放进判断质数的函数中,对返回值判断得出答案。
代码实现
#include <stdio.h>
#include <string.h>
int judge(int n)//判断是否为质数 {
if (n < 2)
return 0;
if (n == 2 || n == 3)
return n;
for (int i = 2; i < n; i++) {
if (n % i == 0)
return 0;
if (i == n - 1)
return n;
}
}
int main()
{
char a[110];
scanf("%s", a);
int table[26];
memset(table, 0, sizeof(table));//初始化数组,用于存放字幕出现的次数
for (int i = 0; i < strlen(a); i++) {
table[a[i] - 'a']++;
}//每出现一次,记录该字母的元素加一
int max = 0;
int min = 999;
for (int i = 0; i < 26; i++) {
if (table[i] == 0)//为0说明不出现,不能作为最小值,跳过
continue;
if (table[i] < min)
min = table[i];
if (table[i] > max)
max = table[i];
}
int n = max - min;
int m = judge(n);
if (m > 0) {
printf("Lucky Word\n");
printf("%d", m);
}
else {
printf("No Answer\n");
printf("%d",m);
}
}
拯救oibh总部
题目链接:P1506拯救obih总部
题目描述
oibh 被突来的洪水淹没了,还好 oibh 总部有在某些重要的地方起一些围墙。用 *
号表示,而一个四面被围墙围住的区域洪水是进不去的。
oibh 总部内部也有许多重要区域,每个重要区域在图中用一个 0
表示。
现在给出 oibh 的围墙建设图,问有多少个没被洪水淹到的重要区域。
输入格式
第一行为两个正整数 x , y x,y x,y。
接下来
x
x
x 行,每行
y
y
y 个整数,由 *
和 0
组成,表示 oibh 总部的建设图。
输出格式
输出没被水淹没的 oibh 总部的 0
的数量。
样例 #1
样例输入 #1
4 5
00000
00*00
0*0*0
00*00
样例输出 #1
1
样例 #2
样例输入 #2
5 5
*****
*0*0*
**0**
*0*0*
*****
样例输出 #2
5
提示
对于 100 % 100\% 100% 的数据, 1 ≤ x , y ≤ 500 1 \le x,y \le 500 1≤x,y≤500。
解题思路
- 本题使用DFS进行解答,本人现在还没学到这里,下次一定补上该块内容
代码实现
下次一定
队列安排
题目链接:P1160 队列安排
题目描述
一个学校里老师要将班上 N N N 个同学排成一列,同学被编号为 1 ∼ N 1\sim N 1∼N,他采取如下的方法:
-
先将 1 1 1 号同学安排进队列,这时队列中只有他一个人;
-
2 ∼ N 2\sim N 2∼N 号同学依次入列,编号为 i i i 的同学入列方式为:老师指定编号为 i i i 的同学站在编号为 1 ∼ ( i − 1 ) 1\sim(i-1) 1∼(i−1) 中某位同学(即之前已经入列的同学)的左边或右边;
-
从队列中去掉 M M M 个同学,其他同学位置顺序不变。
在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。
输入格式
第一行一个整数 N N N,表示了有 N N N 个同学。
第 2 ∼ N 2\sim N 2∼N 行,第 i i i 行包含两个整数 k , p k,p k,p,其中 k k k 为小于 i i i 的正整数, p p p 为 0 0 0 或者 1 1 1。若 p p p 为 0 0 0,则表示将 i i i 号同学插入到 k k k 号同学的左边, p p p 为 1 1 1 则表示插入到右边。
第 N + 1 N+1 N+1 行为一个整数 M M M,表示去掉的同学数目。
接下来 M M M 行,每行一个正整数 x x x,表示将 x x x 号同学从队列中移去,如果 x x x 号同学已经不在队列中则忽略这一条指令。
输出格式
一行,包含最多 N N N 个空格隔开的整数,表示了队列从左到右所有同学的编号。
样例 #1
样例输入 #1
4
1 0
2 1
1 0
2
3
3
样例输出 #1
2 4 1
提示
【样例解释】
将同学 2 2 2 插入至同学 1 1 1 左边,此时队列为:
2 1
将同学 3 3 3 插入至同学 2 2 2 右边,此时队列为:
2 3 1
将同学 4 4 4 插入至同学 1 1 1 左边,此时队列为:
2 3 4 1
将同学 3 3 3 从队列中移出,此时队列为:
2 4 1
同学 3 3 3 已经不在队列中,忽略最后一条指令
最终队列:
2 4 1
【数据范围】
对于 20 % 20\% 20% 的数据, 1 ≤ N ≤ 10 1\leq N\leq 10 1≤N≤10。
对于 40 % 40\% 40% 的数据, 1 ≤ N ≤ 1000 1\leq N\leq 1000 1≤N≤1000。
对于 100 % 100\% 100% 的数据, 1 < M ≤ N ≤ 1 0 5 1<M\leq N\leq 10^5 1<M≤N≤105。
解题思路
- 用数组模拟双向链表,每次输入k,p后判断插入位置,直接插入,当所有k,p输入完成后数组位置也判断完进行过确认。
- 最后判断删除
代码实现
#include<stdio.h>
int n,m;
struct node{
int l,r;
int id;
}a[1000005];
int main(){
scanf("%d",&n);
for(int i=2;i<=n;i++) {//从第二行开始,将i号学生插到k号的一边
int k,p;
scanf("%d %d",&k,&p);
if (p == 1) {//插在右边
a[i].r=a[k].r;
a[i].l=k;
a[a[k].r].l=i;
a[k].r=i;
}
else{//插在左边
a[i].l=a[k].l;
a[i].r=k;
a[a[k].l].r=i;
a[k].l=i;
}
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
int x;
scanf("%d",&x);
a[x].id=1;//标记要删除的人
}
int now;
for(int i=1;i<=n;i++) {
if(a[i].l==0&&a[i].id!=1)
now=i;
}
while(now){//如果now存在的话
if(a[now].id==0) printf("%d ",now);
now=a[now].r;//下一个
}
return 0;
}
T3 句子反转
题目链接:B3640 T3 句子反转
题目背景
请尽量在 30min 之内写完题目。这是指「写代码」的时间;「读题」时间不计算在内。
题目描述
给定一行句子,每个词之间用空格隔开,要么是全小写英文单词,要么是全大写英文单词,要么是自然数。
要求将这些单词倒序输出。而且对于每个单词,如果是小写词,应当转为大写;如果是大写词,应当转为小写;如果是自然数,应该倒转输出。
举一个例子:
we choose TO go 2 the 123 moon
程序应当输出:
MOON 321 THE 2 GO to CHOOSE WE
输入格式
仅一行,即需要反转的句子。
输出格式
仅一行,表示程序对句子的处理结果。
样例 #1
样例输入 #1
we choose TO go 2 the 123 moon
样例输出 #1
MOON 321 THE 2 GO to CHOOSE WE
提示
样例解释
首先应当按单词逆序,即:
moon 123 the 2 go TO choose we
小写变大写、大写变小写、倒转自然数之后,得到最终结果:
MOON 321 THE 2 GO to CHOOSE WE
数据规模与约定
对于 100 % 100\% 100% 的数据,句子中包含的单词数量不超过 1000 1000 1000,每个单词长度不超过 6 6 6。
考察知识点
字符串
解题思路
- 首先先将字符串逆置过来,由于是一个英文句子,故可以以单词间空格作为判断节点。
- 从后向前判断,每次遇到空格即判断空格下一个元素的大小写,若为大写则将其全部转化为小写输出,反之,全部转化为大写输出。
- 若遇到非字母元素,则从后向前输出这一部分元素,从而将数字逆过来。
代码实现
#include <stdio.h>
#include <string.h>
int main() {
char s[101000];
gets(s);
int left = strlen(s) - 1;
int right = strlen(s) - 1;
int i = left;
while (i >= 0) {
while (left >= 0 && s[left] != ' ') {//每次遇到空格就停下来输出
left--;
}
int n = left;
left++;
while (left <= right) {
if (s[right] >= '0' && s[right] <= '9') {
printf("%c", s[right]);
right--;
}//数字直接逆序输出
else if (s[right] >= 'a' && s[right] <= 'z') {
printf("%c", s[left] - 32);//转化为大写输出
left++;
}
else if (s[right] >= 'A' && s[right] <= 'Z') {
printf("%c", s[left] + 32);//转化为小写输出
left++;
}
}
left = n - 1;
right = n - 1;
i = n;
printf(" ");//每次输出一个空格间隔单词
}
return 0;
}
[NOIP2006 普及组]明明的随机数
题目链接:P1059 [NOIP2006 普及组] 明明的随机数
题目描述
明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了 N N N 个 1 1 1 到 1000 1000 1000 之间的随机整数 ( N ≤ 100 ) (N\leq100) (N≤100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作。
输入格式
输入有两行,第 1 1 1 行为 1 1 1 个正整数,表示所生成的随机数的个数 N N N。
第 2 2 2 行有 N N N 个用空格隔开的正整数,为所产生的随机数。
输出格式
输出也是两行,第 1 1 1 行为 1 1 1 个正整数 M M M,表示不相同的随机数的个数。
第 2 2 2 行为 M M M 个用空格隔开的正整数,为从小到大排好序的不相同的随机数。
样例 #1
样例输入 #1
10
20 40 32 67 40 20 89 300 400 15
样例输出 #1
8
15 20 32 40 67 89 300 400
提示
NOIP 2006 普及组 第一题
排序算法
解题思路
- 本题给定一个无序数列,要求将其从小到大排序后去掉相同的数据,故而先对整个数组进行排序
- 排序后定义一个变量为0,由于是一个从小到大的数组,遍历一遍判断元素是否与上一个元素相等,若相等,变量不变;若不想等,则变量加1,变量最后的值即为不同元素的个数
- 最后输出数组同上,元素与上一个相同则不输出,不同则输出元素
代码实现
#include <stdio.h>
void bubble(int a[], int n) {
for (int j = n - 1; j > 0; j--) {
for (int i = 0; i <= j; i++) {
if (a[i] > a[i + 1]) {
int swap = a[i];
a[i] = a[i + 1];
a[i + 1] = swap;
}
}
}
}
int main()
{
int n;
scanf("%d", &n);
int a[1000] = { 0 };
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
bubble(a, n);//冒泡排序,从小到大排序数组
int m = n;
for (int i = 1; i <= n; i++) {
if (i >= 2) {
if (a[i] == a[i - 1])
m--;
}
}
printf("%d\n", m);
for (int i = 1; i <= n; i++) {
if (i >= 2) {
if (a[i] == a[i - 1])
continue;
}
printf("%d ", a[i]);
}
return 0;
}
P3817 小A的糖果
题目链接:P3817 小A的糖果
题目描述
小 A 有 n n n 个糖果盒,第 i i i 个盒中有 a i a_i ai 颗糖果。
小 A 每次可以从其中一盒糖果中吃掉一颗,他想知道,要让任意两个相邻的盒子中糖的个数之和都不大于 x x x,至少得吃掉几颗糖。
输入格式
输入的第一行是两个用空格隔开的整数,代表糖果盒的个数 n n n 和给定的参数 x x x。
第二行有 n n n 个用空格隔开的整数,第 i i i 个整数代表第 i i i 盒糖的糖果个数 a i a_i ai。
输出格式
输出一行一个整数,代表最少要吃掉的糖果的数量。
样例 #1
样例输入 #1
3 3
2 2 2
样例输出 #1
1
样例 #2
样例输入 #2
6 1
1 6 1 2 0 4
样例输出 #2
11
样例 #3
样例输入 #3
5 9
3 1 4 1 5
样例输出 #3
0
提示
样例输入输出 1 解释
吃掉第 2 盒中的一个糖果即可。
样例输入输出 2 解释
第 2 盒糖吃掉 6 6 6 颗,第 4 盒吃掉 2 2 2 颗,第 6 盒吃掉 3 3 3 颗。
数据规模与约定
- 对于 30 % 30\% 30% 的数据,保证 n ≤ 20 n \leq 20 n≤20, a i , x ≤ 100 a_i, x \leq 100 ai,x≤100。
- 对于 70 % 70\% 70% 的数据,保证 n ≤ 1 0 3 n \leq 10^3 n≤103, a i , x ≤ 1 0 5 a_i, x \leq 10^5 ai,x≤105。
- 对于 100 % 100\% 100% 的数据,保证 2 ≤ n ≤ 1 0 5 2 \leq n \leq 10^5 2≤n≤105, 0 ≤ a i , x ≤ 1 0 9 0 \leq a_i, x \leq 10^9 0≤ai,x≤109。
考察知识点
贪心算法
解题思路
- 该题是一道贪心算法的问题,要让任意相邻两盘糖果数量小于目标值,则每次都先吃掉靠后一盘糖果
- 当每次都先吃掉后一盘糖果,这样可以让下次判断时总数减小,达到吃最少糖果的目的
代码实现
#include <stdio.h>
int main() {
long long a[100000];
long long n, m;
scanf("%lld %lld", &n, &m);
for (int i = 0; i < n; i++) {
scanf("%lld", &a[i]);
}//输入数据
long long j = 0;
for (int i = 0; i < n - 1; i++) {
int k = 0;
if (a[i] + a[i + 1] <= m)//如果小于目标值,直接跳过该元素的判断
continue;
if (a[i] + a[i + 1] > m) {
k = a[i] + a[i + 1] - m;//定义应该吃掉糖果的数量
if (k <= a[i+1]) {//判断吃该元素下一盘能否满足要求
a[i + 1] -= k;
j += k;
}
else {
a[i] = k - a[i + 1];
a[i + 1] = 0;
j += k;
}
}
}
printf("%lld", j);
return 0;
}