目录
前言
- 该题单网址如下:牛客竞赛语法入门班选择结构习题
- 该题单面向的是没有什么经验的初学者,如果编程基础较好的人就不用做这些题了。
- 在这篇博客中,我会讲解几道陷阱题和比较难的题,一些水题我会直接跳过。
- 陷阱题我不会放代码,因为这种题的代码简单,要注意的点就在陷阱本身。
题目:
(1)、陷阱题:C-默契
1、题目描述
经过无数次Wa~~以后,小财终于理解了二分查找,终于可以出去玩了。 正好这时小金来找他玩猜数字的游戏,
每个人随即说出一个数字,若两数字相等输出“Tacit!”(不包括引号),否则输出“No Tacit!”(不包括引号)。
2、输入描述
两个整数x 和 y(在int范围内),分别代表小金和小财说出的数字
3、本题需要注意的点
- Tacit!中的感叹号!是中文的
- NO Tacit!中的感叹号!是英文的
只要注意到了这个,这题问题就不大了。
(2)、陷阱题:E-CSimplemathproblem
1、题目描述
这一节课,Priest给大家做了一个小测试。 老师给了你两个正整数X, Y。并按照一下规则做运算,求出答案Z。 如果X是Y的因数,则Z等于X+Y。否则Z = Y - X。
2、输入描述:
输入两个正整数X, Y。 (1 <= X <= Y <= 100000000000000)。
3、本题需要注意的点
xy的取值范围为1~100000000000000,而在64位机器上,int的取值范围为 -2147483648~2147483647 ,即(-2^15 ~ 2^15-1)。所以要用long long类型定义x,y变量。
(3)、有点难:H-小名的回答
1、题目描述
总算到暑假了,小姐姐是非常的闲,所以想去找梅溪湖的小名玩,可是她从没去过梅溪湖,所以只能凭小名告诉她的地方走,每次只能向上下左右四个方向走1步。小姐姐的坐标为(0,0),小名在(a,b),小姐姐有点近视,小名也有点近视。所以到了(a,b)也不一定能和小名会面,不过还好,小姐姐最后找到了小名。小姐姐想要小名知道自己来一趟是多么不容易,所以在聊天的过程中小姐姐说自己为了到这里走了n步。小名,你觉得她说的可能是真话么。有可能就输出YES,否则输出NO(如果用random的话,小姐姐觉得你好像不在意她,明年暑假就不来了)
2、输入描述
a,b,n(-1000<=a,b<=1000,a*b>0,1<=n<=2000)
3、题解
先总结题目要点。
- 小姐姐可以多次走过(a,b)
- 小姐姐最后的位置在(a,b)
因此,只要小姐姐走了n步,最终的位置有可能在(a,b),就输出YES,
如果不可能在(a,b),就输出NO
分析:我们引入初中的平面直角坐标系来研究这道题。
如果小姐姐向右走一步,她的坐标变为(1,0)
再向上走一步,她的坐标变为(1,1)。走到这里,我们用了1+1 即2步
总结:如果要走到(a,b)点,至少要a+b步如果小姐姐想从(1,1)再次回到(1,1)点(有可能是她近视,第一次没有发现小名),最简单的方法就是向着任一方向走一步,再原路返回。这需要小姐姐走两步。这个步骤可以重复进行(每一次走的都是偶数步),直到小姐姐看到小名为止。
总结:到了(a,b)之后,小姐姐可以选择不接着走,也可以选择继续走n步回到(a,b).
从(0,0)到(a,b)步数n的取值可以为:a+b,a+b+2,a+b+4……
4、代码
#include<iostream>
using namespace std;
int main()
{
int a,b,n;
cin>>a>>b>>c;
if(n>=a+b){
if((n-a-b)%2==0){
printf("YES");
}
else{
printf ("NO");
}
}
else { //a+b<n
printf("NO");
}
return 0;
}
(4)、有点难:N-送分题
1、题目描述
数据结构之神ccz又在出毒瘤数据结构了 神出了这样一个题:
给你三个数,在这三个数中间任意加*或者是+,然后可以随便打括号,只要这个表达式合法 比如说1 2 3可以得到:
1+2 * 3=7
1 * (2+3)=5
1 * 2 * 3=6
(1+2)*3=9
不能改变这三个数的原顺序 最大化表达式的值
2、预备知识
c++自带了求最大值函数max,在内存空间std里面
作用是返回两个数的最大值
3、题解
我们来看看三个数有几种组合
- a+b+c
- a+b*c
- (a+b)*c
- a*b+c
- a*(b+c)
- a* b*c
我们要在这六种组合中找到最大值
4、代码
理解这串代码应该没什么难度
#include<iostream>
using namespace std;
int main()
{
int a,b,c,mx;
cin>>a>>b>>c;
mx=a+b+c; //把第一组的值赋给变量mx
mx=max(mx,(a+b)*c); //思路:只要发现之后的组合数值有比第一组大的
mx=max(mx,(c+b)*a); // 就把大的值赋给mx
mx=max(mx,a*b*c);
mx=max(mx,a*b+c);
mx=max(mx,b*c+a);
cout <<mx;
return 0;
}
(5)、 比较难:Q前天是哪天
1、题目描述
输入在一个日期,格式如"yyyy-mm-dd",题目保证所有输入日期为合法日期。
2、输入描述
在一行中输出日期,格式如"yyyy-mm-dd"。
3、预备知识
(1)、日期的输入:我们在输入日期的时候,输入的是带有 - 的一串数字
- 如果我们用cin语句输入,结果就会有BUG。
#include<iostream>
using namespace std;
int main() {
int x, y, z;
cin >> x >> y >> z;
}
如上图:y的值为-10,z的值为-11,与我们想要的结果不符。
- 要正确输入数字,这里就要用到scanf语句。
这里先补充一下scanf语句的特殊之处:
- scanf函数允许把普通字符放在格式字符串之中,除了空格字符外的普通字符必须与输入字符串严格匹配。
scanf("%d,%d",&m,&n);
用户的输入格式为 20,60
- 我们可以把上面的代码改为:
int main() {
int x, y, z;
scanf("%d-%d-%d",&x,&y,&z);
// " "里的东西是格式字符串, -是普通字符
}
原理:scanf函数允许把普通字符放在格式字符串之中,除了空格字符外的普通字符必须与输入字符串严格匹配。
(2)、创建代表每个月份天数的数组
char mday[12]={31,28,31,30,31,30,31,31,30,31,30,31}; //这样可以
但为了更直观,我们想要数组的下标与月份相对应。
可以这么创建数组
char mday[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
(3)、打印的格式
如果月份是个位数(如 8),我们要打印 08,而不是8
需要补充printf()的转换说明标志符的概念
- %数字d 表示打印的最小字段宽度,
如:printf(“%2d”,4); 打印结果为 4(空格4)。- %.数字d 对于整形转换,表示待打印数字的最小位数。 如有必要,使用前导0来达到这个位数
如:printf(“%.2d”,4);打印结果为04;
4、代码
int main() {
int year, month, day;
cin >> year >> month >> day;
int mday[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
mday[2] = 29; //判断是否为闰年,如果是,二月的天数变为29天
if (day > 2) {
day -= 2;
}
else if (month > 1) { //如果day<=2,并且month>1
month -= 1; //这个语句执行后,month的值-1
day = day + mday[month] - 2;
}
else { //如果day<=2,并且mouth=1
year -= 1;
month = 12;
day = 29 + day;
}
printf("%d-%.2d-%.2d", year, month, day);
}
(6)、数学题:S-纸牌
1、 题目描述
小w想和你van纸牌
小w有两张纸牌,两张纸牌上都有相同的正整数n
每一轮一张纸牌上的数都可以减去小于等于另外一张纸牌上的数的数
每一轮只能操作和上轮不同的纸牌
小w想知道三轮之后两纸牌上数字之和的最小值
注意,不能减为负数
2、题解
代码不难,但是证明比较难
这是网上找的题解,应该可以解决问题。
(7)、有点难:T-排队领水
1、题目描述
羊村的供水系统搞砸了,隔壁牛村捐赠的的矿泉水刚刚送达,村长让喜羊羊们排队领水,已知有n个羊村村民正在排队取水,懒羊羊不知道他在队伍的具体哪个位置,但他知道有不少于a个人在他前面,有不多于b个人在他后面,你能帮忙计算一下懒羊羊有多少个可能的位置吗?
2、输入描述
输入一行包含三个整数n,a,b
0<= a,b < n <= 100
3、题解
首先,先理解一下题目的意思
总结:
- a+b<n 懒羊羊可能有b+1个位置
- a+ b>= n 懒羊羊可能有b-(a+b-n)个位置
4、代码
#include<iostream>
using namespace std;
int main(){
int n,a,b;
cin>>n>>a>>b;
if(a+b<n){
cout<<b+1;
}else if(a+b>=n){
int m = a+b-n;
cout<<b-m;
}
}
(8)、有点难:u-可编程拖拉机比赛
我个人觉得这题不好写,但通过率还挺高的
1、题目描述
“这个比赛,归根结底就是控制一个虚拟的小拖拉机跑完整个赛道。一般一场比赛会有 9 个到 13 个赛道,最后看能跑完多少个赛道。”
通常在一场可编程拖拉机比赛中,分别会有实际参赛队伍数 10%、20%、30%
向下取整的队伍获得金、银、铜牌,其余队伍获得荣誉提名,俗称“铁牌”。
但是主办方往往会多准备一些奖牌,那么在发奖牌的时候会按照比例向上取整发出的奖牌以减少浪费,就会有一些原本获得银牌的队伍获得了金牌。
现在给出一个赛区的规模,也就是这个赛区的实际参赛队伍数,小 Q 同学想知道有多少队伍的奖牌会由银变金、由铜变银、由铁变铜。
2、输入描述
输入只有一行,包含一个整数 n (10 <= n <= 1000),表示实际参赛队伍数
3、预备知识
1、向下取整。只要用int类型声明小数就行了
如:int a = 4.6; a的值为4,不遵循四舍五入
2、向上取整。需要用到库函数ceil,这个函数在
头文件 cmath 里。
4、代码
#include<iostream>
#include<cmath>
using namespace std;
int main(){
int n;
cin>>n;
int a = n*0.1;
int b = n*0.2;
int c = n*0.3;
a = ceil(n*0.1)-a;
b = ceil(n*0.2)-b+a; //个人觉得这句不好理解
c = ceil(n*0.3)-c+b; //还有这句
cout<<a<<" "<<b<<" "<<c;
}
5、解释
所以:银变金 == 多的金牌数
铜变银 == 多的金牌数 +多的银牌数
铁变铜 ==多的金牌数 +多的银牌数+多的铜牌数
总结
此刻我只有一种感觉