3.1 简单模拟

(1)B1032

为了用事实说明挖掘机技术到底哪家强,PAT 组织了一场挖掘机技能大赛。现请你根据比赛结果统计出技术最强的那个学校。

输入格式:

输入在第 1 行给出不超过 105 的正整数 N,即参赛人数。随后 N 行,每行给出一位参赛者的信息和成绩,包括其所代表的学校的编号(从 1 开始连续编号)、及其比赛成绩(百分制),中间以空格分隔。

输出格式:

在一行中给出总得分最高的学校的编号、及其总分,中间以空格分隔。题目保证答案唯一,没有并列。

输入样例:

6
3 65
2 80
1 100
2 70
3 40
3 0

输出样例:

2 150

题解:

难度很低的题往往笑里藏刀~
(1)WA:下面代码的pos初值不能设为0,根据题意肯定是个正整数,万一数据只有一行,且分数为0呢,此时应该输出1,而你输出pos原始值0,嗐,WA了
(2)超时:不要傻傻地用二重循环,你肯定能发现其实total数组的下标就是学校的标号,因此一次循环就OK。

  1. #include <iostream>
  2. using namespace std;
  3. struct comp{
  4. int num;
  5. int grade;
  6. }cmp[100001];
  7. int total[100001]={0};
  8. int main()
  9. {
  10. int n;
  11. cin>>n;
  12. for(int i=1;i<=n;++i){
  13. scanf("%d",&cmp[i].num);
  14. scanf("%d",&cmp[i].grade);
  15. total[cmp[i].num]+=cmp[i].grade;
  16. }
  17. int pos=1;
  18. for(int i=1;i<=n;++i){
  19. if(total[pos]<total[i]){
  20. pos = i;
  21. }
  22. }
  23. printf("%d %d",pos,total[pos]);
  24. return 0;
  25. }

(2)3-1-A

题目描述

有一个长度为整数L(1<=L<=10000)的马路,可以想象成数轴上长度为L的一个线段,起点是坐标原点,在每个整数坐标点有一棵树,即在0,1,2,…,L共L+1个位置上有L+1棵树。
现在要移走一些树,移走的树的区间用一对数字表示,如 100 200表示移走从100到200之间(包括端点)所有的树。
可能有M(1<=M<=100)个区间,区间之间可能有重叠。现在要求移走所有区间的树之后剩下的树的个数。

输入

两个整数L(1<=L<=10000)和M(1<=M<=100)。
接下来有M组整数,每组有一对数字。

输出

可能有多组输入数据,对于每组输入数据,输出一个数,表示移走所有区间的树之后剩下的树的个数。

样例输入

4 2
1 2
0 2
11 2
1 5
4 7
0 0

样例输出

2 5

题解:
这道题如果读者的思路是,每次输入判断是不是和之前有重叠,如果这样重叠该怎么办,那样重叠该怎么办······ 那估计是gg了。
笔者认为比较合理的做法是:设一个数组,把a[0]~a[L]都设成1,每组输入就把区间内的元素改为0.不管重不重叠,这样,最后只需求数组的sum即为最后的AC代码~

  1. #include <cstdio>
  2. int main()
  3. {
  4. int L;
  5. int m;
  6. while (scanf("%d %d",&L,&m)!=EOF){
  7. if(L==0&&m==0) break;
  8. int i,sum=0;
  9. int a[L+1];
  10. for(i=0;i<L+1;++i){
  11. a[i]=1;
  12. }
  13. for(int k=0;k<m;++k){
  14. int s,t;
  15. scanf("%d %d",&s,&t);
  16. for(int j=s;j<=t;++j){
  17. a[j]=0;
  18. }
  19. }
  20. for(int k=0;k<L+1;++k){
  21. sum+=a[k];
  22. }
  23. printf("%d\n",sum);
  24. }
  25. return 0;
  26. }

(3)3-2-B

题目描述

给定两个整数A和B,其表示形式是:从个位开始,每三位数用逗号”,”隔开。
现在请计算A+B的结果,并以正常形式输出。

输入

输入包含多组数据数据,每组数据占一行,由两个整数A和B组成(-10^9 < A,B < 10^9)。

输出

请计算A+B的结果,并以正常形式输出,每组数据占一行。

样例输入

-234,567,890 123,456,789
1,234 2,345,678

样例输出

-111111101
2346912

题解:

(1)记住字符转数字函数
(2)字符1和数字1 ASC相差48
(3)char数组最后会有\0结尾,因此要多给一个空间,至少开辟13个长度

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. long transform(char *a,int len);//将数组转化为整型
  5. int main()
  6. {
  7. char a[13],b[13];
  8. int len1,len2;
  9. long A,B;
  10. while(scanf("%s%s",a,b)!=EOF)
  11. {
  12. len1=strlen(a);
  13. len2=strlen(b);
  14. A=transform(a,len1);
  15. B=transform(b,len2);
  16. printf("%ld\n",A+B);
  17. }
  18. return 0;
  19. }
  20. long transform(char *a,int len)
  21. {
  22. int sum=0,j=1,i;
  23. for(i=len-1; i>=0; i--)
  24. {
  25. if(a[i]>='0'&&a[i]<='9')
  26. {
  27. sum+=(a[i]-48)*j;
  28. j*=10;
  29. }
  30. }
  31. if(a[0]=='-')
  32. sum=-sum;
  33. return sum;
  34. }

3.2 查找元素

(1)3-2-B

题目描述

输入一个数n,然后输入n个数值各不相同,再输入一个值x,输出这个值在这个数组中的下标(从0开始,若不在数组中则输出-1)。

输入

测试数据有多组,输入n(1<=n<=200),接着输入n个数,然后输入x。

输出

对于每组输入,请输出结果。

样例输入

4
1 2 3 4
3

样例输出

2

题解:

题不难,陷阱不少,需要注意的地方很多,这道题codeup网站上AC率只有20%多一点,其他题多数是65%以上,一般错我都是因为考虑不全导致WA。
(1)忽略-1导致WA:题里说啦,不在数组中输出-1,别不做处理!!!!
(2)忽略多组输入:不知道黑盒数据有多少,要用EOF,不是只有一组输入 !!
(3)忽略换行\n : 多数题目只有1个输出就结束程序,即使不加\n也一样AC,导致学生习惯不加最后的\n, 这道题就不一样,多组输入,不加\n,会出问题。

  1. #include <cstdio>
  2. int a[202];
  3. int main()
  4. {
  5. int n;
  6. while (scanf("%d",&n)!=EOF){
  7. for(int i=0;i<n;++i){
  8. scanf("%d",&a[i]);
  9. }
  10. int key;
  11. scanf("%d",&key);
  12. for(int i=0;i<n;++i){
  13. if (key == a[i]){
  14. printf("%d\n", i);
  15. break;
  16. }
  17. if (i == n - 1 && key != a[i]){
  18. printf("-1\n");
  19. }
  20. }
  21. }
  22. return 0;
  23. }

3.4 日期处理

(1) 3-4-A

题目描述

有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天。

输入

有多组数据,每组数据有两行,分别表示两个日期,形式为YYYYMMDD

输出

每组数据输出一行,即日期差值

样例输入

20130101
20130105

样例输出

5

题解:

(1)日期的输入只有8位,当作int处理更方便(字符串很麻烦),然后通过%和/ 分离出年月日,再进一步处理
(2)总思路:把date1不断的++(只要date1<date2),d1达到当月天数上限,就置1,m1++,当m1达到13时,m1之1,y1++
(3)为了更加方便地取出当月的天数,我们设计isLeap函数判断平年闰年,并用二维数组a[13][2]存储天数,a[][0]表示平年,a[][1]表示闰年

  1. //3-4-A (日期差值)
  2. #include <cstdio>
  3. bool isLeap (int y){
  4. return ((y%4==0&&y%100!=0)||(y%400==0));
  5. }
  6. int main()
  7. {
  8. //a[][0]是平年 a[][1]是闰年
  9. int month[13][2]={{0,0},{31,31},{28,29},{31,31},{30,30},{31,31},{30,30},
  10. {31,31},{31,31},{30,30},{31,31},{30,30},{31,31}};
  11. int date1,date2;
  12. while (scanf("%d%d",&date1,&date2)!=EOF)
  13. {
  14. if (date1 > date2)
  15. {
  16. int temp = date2;
  17. date2 = date1;
  18. date1 = temp;
  19. }
  20. if (date1 == date2)
  21. {
  22. printf("1\n");
  23. }
  24. if (date1 < date2)
  25. {
  26. int sum = 1;
  27. int y1, m1, d1;
  28. int y2, m2, d2;
  29. y1 = date1 / 10000;
  30. m1 = (date1 % 10000) / 100;
  31. d1 = date1 % 100;
  32. y2 = date2 / 10000;
  33. m2 = (date2 % 10000) / 100;
  34. d2 = date2 % 100;
  35. while (y1 < y2 || m1 < m2 || d1 < d2)
  36. {
  37. d1++;
  38. if (d1 == (month[m1][isLeap(y1)]) + 1)
  39. {
  40. m1++;
  41. d1 = 1;
  42. }
  43. if (m1 == 13)
  44. {
  45. y1++;
  46. m1 = 1;
  47. }
  48. sum++;
  49. }
  50. printf("%d\n", sum);
  51. }
  52. }
  53. return 0;
  54. }

3.5 进制转换

综述:进制转换主要分为(P进制转十进制&十进制转P进制)

image.png

  1. // 将P进制数x转换为十进制数y
  2. int y = 0, product = 1; //product在循环中不断乘P,得到1、P、P^2、P^3 ···
  3. while(x!=0){
  4. y = y + (x%10)*product; // 每次把x的最后一位乘product
  5. x = x/10; // 把x去掉个位
  6. product = product*P;
  7. }

CF11FDA36C8DD6F122795539B14E5764.jpg

  1. // 将十进制数y转换为Q进制,结果存放于数组z
  2. int z[40], num = 0;
  3. do{
  4. z[num] = y%Q; //除基取余
  5. ++num;
  6. y = y/Q;
  7. }while(y!=0); //当商不为0时进行循环

这样操作后,结果就倒序存在数组中,即z数组从高位z[num-1]到低位z[0]即为Q进制z,进制转换完成。

(1)3-5-A

题目描述

输入两个不超过整型定义的非负10进制整数A和B(<=231-1),输出A+B的m (1 < m <10)进制数。

输入

输入格式:测试输入包含若干测试用例。每个测试用例占一行,给出m和A,B的值。
当m为0时输入结束。

输出

输出格式:每个测试用例的输出占一行,输出A+B的m进制数。

样例输入

2 4 5
8 123 456
0

样例输出

1001
1103

提示

注意输入的两个数相加后的结果可能会超过int和long的范围。

题解:

Nothing to say. Just notice the notice and design the type of (a+b) as “unsigned int”.

  1. #include <cstdio>
  2. int main()
  3. {
  4. int a,b,d;
  5. unsigned int c;
  6. while (true){
  7. int r[50]={0},num=0;
  8. scanf("%d",&d);
  9. if(d==0){
  10. break;
  11. }
  12. scanf("%d%d",&a,&b);
  13. c = a+b;
  14. do{
  15. r[num] = c%d;
  16. ++num;
  17. c = c/d;
  18. }while (c!=0);
  19. for(int i=num-1;i>=0;--i){
  20. printf("%d",r[i]);
  21. }
  22. printf("\n");
  23. }
  24. return 0;
  25. }

3.6 字符串处理

给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。

输入格式:

测试输入包含一个测试用例,在一行内给出总长度不超过 80 的字符串。字符串由若干单词和若干空格组成,其中单词是由英文字母(大小写有区分)组成的字符串,单词之间用 1 个空格分开,输入保证句子末尾没有多余的空格。

输出格式:

每个测试用例的输出占一行,输出倒序后的句子。

输入样例:

Hello World Here I Come

输出样例:

Come I Here World Hello

  1. #include <cstdio>
  2. #include <cstring>
  3. int main()
  4. {
  5. char ans[1000][1000];
  6. int num = 0;
  7. while (scanf("%s",ans[num])!=EOF){
  8. ++num;
  9. }
  10. for(int i=num-1;i>=0;--i){
  11. printf("%s",ans[i]);
  12. if(i>0) printf(" ");
  13. }
  14. return 0;
  15. }