经验技巧套路收获总结(附上ccf第二类中的三道)

来源:互联网 发布:java 包装类 编辑:程序博客网 时间:2024/06/05 03:54

1.字符串末尾的\0也有一个长度。字符我们最好用数组来记住空格的位置而不是记住单词的长度。

2.串结束标志是\0不是\n

3.一段单词中通过==‘ ’来判断空格。

4,小技巧:对于一个数组向右循环右移这种问题

   思想:就是向右移,其实我们可以分成三个部分来完成。从起点到总长度-右移长度(取模之后的)进行一次依次交换。把剩下的后一半进行一次依次交换,最后把所有的再进行一次依次交换。

   这是一个重要的想法,我们可以记忆掌握

5这里我想解释的是数组做为形参在函数声明里面的格式及形式及为什么?

  1)//a 代表的数据首元素的地址 (首元素),同时与整个数组地址重合,但其不能代表整个数组,只能代表起始个体的地址  即    数组的首地址

  2)//&a代表的是整个数组的地址   (特别特别的注意) 它的加1是以整块数组所占字节数总数为单位1  即整个数组的地址

  3) 由此引出声明数组参量

    前提:实际参数是一个数组名。C对于int a  [ ] 和 int * a作了同样解释,a是指向int的指 针              。 (即两种形势在函数声明里面都是可以的。) 

     4) 由于原型允许省略名称,因此下列4种原型都是等价的。

/**   函数原型声明4中等价形式

int sum (int *a , int n)

int sum (int * , int )

int sum (int a[] , int n)

int sum (int [] , int )   //可能略微不熟悉的一种

详情见:点击打开链接  http://blog.csdn.net/jin13277480598/article/details/51891816

6.对于有些题目要求前面几行数据测试后又空行,而最后一行却没有。

空格控制输出每个数据后有一个空格,但是末尾却没有)

这其实也是程序巧妙之处:有while还在执行时我们就定义一个flag标志,有标志我们就printf(  )否则就没有。这也是需要记忆掌握的地方。

7.在数据结构书上观察到一个重要思想,要是理解透,对于一些题就可以应用自如。

二取一再完善思维(暂且起这个名字):

题意:就是有a,b两个数组或者 两个队列。(我暂且只熟悉数组,以此为例),我们需要把两个数组合并为从小到大的数组c。

   1)先将a数组sort从小到大排序

   2)将b数组按从小到大排序

   3)每次循环,都只从a和b数组中各取一个数进行比较,把小的值放在c数组里面,注意自增

   4)重复3)的过程。

   5)当某一个结束,把另外一个数组全部移动到c数组里面,结束。

   讲到上面这个重要思想,现在我们就可以趁热打铁训练一下了。


试题编号:201709-2试题名称:公共钥匙盒时间限制:1.0s内存限制:256.0MB问题描述:

问题描述
  有一个学校的老师共用N个教室,按照规定,所有的钥匙都必须放在公共钥匙盒里,老师不能带钥匙回家。每次老师上课前,都从公共钥匙盒里找到自己上课的教室的钥匙去开门,上完课后,再将钥匙放回到钥匙盒中。
  钥匙盒一共有N个挂钩,从左到右排成一排,用来挂N个教室的钥匙。一串钥匙没有固定的悬挂位置,但钥匙上有标识,所以老师们不会弄混钥匙。
  每次取钥匙的时候,老师们都会找到自己所需要的钥匙将其取走,而不会移动其他钥匙。每次还钥匙的时候,还钥匙的老师会找到最左边的空的挂钩,将钥匙挂在这个挂钩上。如果有多位老师还钥匙,则他们按钥匙编号从小到大的顺序还。如果同一时刻既有老师还钥匙又有老师取钥匙,则老师们会先将钥匙全还回去再取出。
  今天开始的时候钥匙是按编号从小到大的顺序放在钥匙盒里的。有K位老师要上课,给出每位老师所需要的钥匙、开始上课的时间和上课的时长,假设下课时间就是还钥匙时间,请问最终钥匙盒里面钥匙的顺序是怎样的?
输入格式
  输入的第一行包含两个整数NK
  接下来K行,每行三个整数wsc,分别表示一位老师要使用的钥匙编号、开始上课的时间和上课的时长。可能有多位老师使用同一把钥匙,但是老师使用钥匙的时间不会重叠。
  保证输入数据满足输入格式,你不用检查数据合法性。
输出格式
  输出一行,包含N个整数,相邻整数间用一个空格分隔,依次表示每个挂钩上挂的钥匙编号。
样例输入
5 2
4 3 3
2 2 7
样例输出
1 4 3 2 5
样例说明
  第一位老师从时刻3开始使用4号教室的钥匙,使用3单位时间,所以在时刻6还钥匙。第二位老师从时刻2开始使用钥匙,使用7单位时间,所以在时刻9还钥匙。
  每个关键时刻后的钥匙状态如下(X表示空):
  时刻2后为1X345;
  时刻3后为1X3X5;
  时刻6后为143X5;
  时刻9后为14325。
样例输入
5 7
1 1 14
3 3 12
1 15 12
2 7 20
3 18 12
4 21 19
5 30 9
样例输出
1 2 3 5 4
评测用例规模与约定
  对于30%的评测用例,1 ≤ NK ≤ 10, 1 ≤ w ≤ N, 1 ≤ sc ≤ 30;
  对于60%的评测用例,1 ≤ NK ≤ 50,1 ≤ w ≤ N,1 ≤ s ≤ 300,1 ≤ c ≤ 50;
  对于所有评测用例,1 ≤ NK ≤ 1000,1 ≤ w ≤ N,1 ≤ s ≤ 10000,1 ≤ c ≤ 100。
 

//ccf-201709-2-公共钥匙盒#include<bits/stdc++.h>using namespace std; int main(){int start[10000]={0},w[10000]={0},end[10000]={0},num[1000]={0},num1[10000]={0},num2[10000]={0},exist[10000]={0};int i,j,k,n,temp,g;cin>>n>>k;//n个钥匙编号,k个老师使用for(i=0;i<k;i++){cin>>num[i]>>start[i]>>w[i];num1[i]=num2[i]=num[i];} for(i=0;i<n;i++){exist[i]=i+1;}for(i=0;i<k;i++){end[i]=start[i]+w[i];}for(i=0;i<k-1;i++){for(j=0;j<k-1-i;j++){if(start[j]>start[j+1]){swap(start[j],start[j+1]);    swap(num1[j],num1[j+1]);}}}//for(i=0;i<k;i++)//cout<<num1[i]<<endl;for(i=0;i<k-1;i++){for(j=0;j<k-1-i;j++){if(end[j]>end[j+1])    {  swap(end[j],end[j+1]);  swap(num2[j],num2[j+1]);    }    if(end[j]==end[j+1])    {    if(num2[j]>num2[j+1])    {     swap(num2[j],num2[j+1]);    }    }}}i=j=0;while(i<k&&j<k){if(start[i]<end[j]){for(g=0;g<n;g++){if(exist[g]==num1[i]){exist[g]=0;break;}}i++;}else{for(g=0;g<n;g++){if(exist[g]==0){exist[g]=num2[j];break;}}j++;}}while(j<=k){for(g=0;g<n;g++){if(exist[g]==0){exist[g]=num2[j];break;}}j++;}for(i=0;i<n;i++){cout<<exist[i]<<' ';}return 0;} 
现在我来讲讲在编写这道题目时的一些障碍和误区。。

1.数组开出的范围要满足题目给出的数值大小

2.还钥匙要是一起的话,需要先还编号较的

3.对借钥匙时间和还钥匙时间这两个数组排序时,脑袋突然短路了,导致花了很长时间才看出来。

我以为

for(i=0;i<k-1;i++){if(start[i]>start[i+1]){swap(start[i],start[i+1]);swap(num1[i],num1[i+1]);}}
上面这部分代码只能实现左右相互邻近的两个数的比较,而不能实现整个数组宏观上的从前到后的排序。(吸收经验)

要实现从前到后从小到大的整体排序,我们还是的借助冒泡排序。虽然sort()能实现一步到位排序,但是在实际做题过程

我们需要模拟排序过程并修改相关数据。因此冒泡排序还是十分重要的。这里我就顺手总结一下:

for(i=0;i<k-1;i++){for(j=0;j<k-1-i;j++){if(start[j]>start[j+1]){swap(start[j],start[j+1]);} }}

这个题目我觉得还有一点可以总结的就是exist【】的使用非常好。让思路简单了下来,可以借鉴操作系统的二次实验。


体会到exist[ ]的强大,

顺手粘贴一下ccf的题目:

问题描述
试题编号:201703-2试题名称:学生排队时间限制:1.0s内存限制:256.0MB问题描述:
问题描述
  体育老师小明要将自己班上的学生按顺序排队。他首先让学生按学号从小到大的顺序排成一排,学号小的排在前面,然后进行多次调整。一次调整小明可能让一位同学出队,向前或者向后移动一段距离后再插入队列。
  例如,下面给出了一组移动的例子,例子中学生的人数为8人。
  0)初始队列中学生的学号依次为1, 2, 3, 4, 5, 6, 7, 8;
  1)第一次调整,命令为“3号同学向后移动2”,表示3号同学出队,向后移动2名同学的距离,再插入到队列中,新队列中学生的学号依次为1, 2, 4, 5, 3, 6, 7, 8;
  2)第二次调整,命令为“8号同学向前移动3”,表示8号同学出队,向前移动3名同学的距离,再插入到队列中,新队列中学生的学号依次为1, 2, 4, 5, 8, 3, 6, 7;
  3)第三次调整,命令为“3号同学向前移动2”,表示3号同学出队,向前移动2名同学的距离,再插入到队列中,新队列中学生的学号依次为1, 2, 4, 3, 5, 8, 6, 7。
  小明记录了所有调整的过程,请问,最终从前向后所有学生的学号依次是多少?
  请特别注意,上述移动过程中所涉及的号码指的是学号,而不是在队伍中的位置。在向后移动时,移动的距离不超过对应同学后面的人数,如果向后移动的距离正好等于对应同学后面的人数则该同学会移动到队列的最后面。在向前移动时,移动的距离不超过对应同学前面的人数,如果向前移动的距离正好等于对应同学前面的人数则该同学会移动到队列的最前面。
输入格式
  输入的第一行包含一个整数n,表示学生的数量,学生的学号由1到n编号。
  第二行包含一个整数m,表示调整的次数。
  接下来m行,每行两个整数p, q,如果q为正,表示学号为p的同学向后移动q,如果q为负,表示学号为p的同学向前移动-q。
输出格式
  输出一行,包含n个整数,相邻两个整数之间由一个空格分隔,表示最终从前向后所有学生的学号。
样例输入
8
3
3 2
8 -3
3 -2
样例输出
1 2 4 3 5 8 6 7
评测用例规模与约定
  对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 1000,所有移动均合法。

//ccf-201703-2-学生排队 #include<bits/stdc++.h>using namespace std; int main(){int n,m,a[1001],i,j,k,p[1001],q[1001],exist[1001];cin>>n>>m;for(i=0;i<m;i++){cin>>p[i]>>q[i];}for(i=0;i<n;i++){exist[i]=i+1;}for(i=0;i<m;i++){if(q[i]>0){for(j=0;j<n;j++){if(exist[j]==p[i]){k=j;break;}}for(j=k;j<k+q[i];j++){swap(exist[j],exist[j+1]);}}    else{for(j=0;j<n;j++){if(exist[j]==p[i]){k=j;break;}}for(j=k;j>k+q[i];j--){swap(exist[j],exist[j-1]);}}}for(i=0;i<n;i++){cout<<exist[i]<<' ';}return 0;} 

这道题的思想主要就是运用了我上一个博客写的swap()巧妙用法的思想。


接下来再顺手粘贴一道ccf的题目。


问题描述
试题编号:201612-2试题名称:工资计算时间限制:1.0s内存限制:256.0MB问题描述:
问题描述
  小明的公司每个月给小明发工资,而小明拿到的工资为交完个人所得税之后的工资。假设他一个月的税前工资(扣除五险一金后、未扣税前的工资)为S元,则他应交的个人所得税按如下公式计算:
  1) 个人所得税起征点为3500元,若S不超过3500,则不交税,3500元以上的部分才计算个人所得税,令A=S-3500元;
  2) A中不超过1500元的部分,税率3%;
  3) A中超过1500元未超过4500元的部分,税率10%;
  4) A中超过4500元未超过9000元的部分,税率20%;
  5) A中超过9000元未超过35000元的部分,税率25%;
  6) A中超过35000元未超过55000元的部分,税率30%;
  7) A中超过55000元未超过80000元的部分,税率35%;
  8) A中超过80000元的部分,税率45%;
  例如,如果小明的税前工资为10000元,则A=10000-3500=6500元,其中不超过1500元部分应缴税1500×3%=45元,超过1500元不超过4500元部分应缴税(4500-1500)×10%=300元,超过4500元部分应缴税(6500-4500)×20%=400元。总共缴税745元,税后所得为9255元。
  已知小明这个月税后所得为T元,请问他的税前工资S是多少元。
输入格式
  输入的第一行包含一个整数T,表示小明的税后所得。所有评测数据保证小明的税前工资为一个整百的数。
输出格式
  输出一个整数S,表示小明的税前工资。
样例输入
9255
样例输出
10000
评测用例规模与约定
  对于所有评测用例,1 ≤ T ≤ 100000。

这道题,对题意的理解和思路上并没有什么困恼的,但是有一点很容易忽视,而且出手致命,发现不了。

最开始做这道题是,对数据的定义都是int型,但是后面由于乘了小数,变成了float型,但由于我定义的int,后面便导致了一系列搞人的事

虽然错误很小,但是我却发现不了。(后面还闹出一些计算结果不对的笑话,要引起高度注意)

//ccf-201612-2-学生排队 #include<bits/stdc++.h>using namespace std; int main(){int s,i,j,k,a,t,temp;cin>>t;for(s=100;s<11000;s=s+100){if(s<=3500){temp=s;if(temp==t){cout<<s;break;}}if(s>3500&&s<=4500){temp=3500+(s-3500)*97/100;if(temp==t){cout<<s;break;}}if(s>4500&&s<=8000){temp=3500+1500*97/100+(s-4500)*90/100;if(temp==t){cout<<s;break;}}if(s>8000&&s<=12500){temp=3500+1500*97/100+3000*90/100+(s-8000)*80/100;if(temp==t){cout<<s;break;}}if(s>12500&&s<=38500){temp=3500+1500*97/100+3000*90/100+4500*80/100+(s-12500)*75/100;if(temp==t){cout<<s;break;}}if(s>38500&&s<=58500){temp=3500+1500*97/100+3000*90/100+4500*80/100+26000*75/100+(s-38500)*70/100;if(temp==t){cout<<s;break;}}if(s>58500&&s<=83500){temp=3500+1500*97/100+3000*90/100+4500*80/100+26000*75/100+20000*70/100+(s-58500)*65/100;if(temp==t){cout<<s;break;}}if(s>83500){temp=3500+1500*97/100+3000*90/100+4500*80/100+26000*75/100+20000*70/100+25000*65/100+(s-80000)*55/100;if(temp==t){cout<<s;break;}}}return 0;}