NOIP2016复赛解题报告及考后总结

一、题目及分析

买铅笔

题目描述

P老师需要去商店买n支铅笔作为小朋友们参加NOIP的礼物。她发现商店一共有 3种包装的铅笔,不同包装内的铅笔数量有可能不同,价格也有可能不同。为了公平起 见,P老师决定只买同一种包装的铅笔。

商店不允许将铅笔的包装拆开,因此P老师可能需要购买超过n支铅笔才够给小朋友们发礼物。

现在P老师想知道,在商店每种包装的数量都足够的情况下,要买够至少n支铅笔*最少*需要花费多少钱。

输入格式:

输入的第一行包含一个正整数n,表示需要的铅笔数量。

接下来三行,每行用两个正整数描述一种包装的铅笔:其中第一个整数表示这种包装内铅笔的数量,第二个整数表示这种包装的价格。

保证所有的7个数都是不超过10000的正整数。

输出格式:

输出一行一个整数,表示P老师最少需要花费的钱。

样例1输入:

57

2 2

50 30

30 27

样例1输出:

54

 

说明

铅笔的三种包装分别是:

•2支装,价格为2;

•50支装,价格为30

;•30支装,价格为27。

P老师需要购买至少57支铅笔。

如果她选择购买第一种包装,那么她需要购买29份,共计2x29 = 58支,需要花费的钱为2x29 = 58。

实际上,P老师会选择购买第三种包装,这样需要买2份。虽然最后买到的铅笔数 量更多了,为30x2 = 60支,但花费却减少为27 x2 = 54,比第一种少。

对于第二种包装,虽然每支铅笔的价格是最低的,但要够发必须买2份,实际的 花费达到了 30 x 2 = 60,因此P老师也不会选择。所以最后输出的答案是54。

 

样例2输入:

9998

128 233

128 2333

128 666

样例2输出:

18407

样例3输入:

9999

101 1111

1 9999

1111 9999

样例3输出:

89991

【子任务】子任务会给出部分测试数据的特点。如果你在解决题目中遇到了困难,可以尝试只解决一部分测试数据。每个测试点的数据规模及特点如下表:



上表中“整倍数”的意义为:若为“V”,表示对应数据所需要的铅笔数量n定是每种包装铅笔数量的整倍数(这意味着一定可以不用多买铅笔)。

分析:

这道题比较简单,直接用除法,再向上取整,乘上单价,找出最小的数。

 

#include<cstdio>
#include<cmath>
int main()
{
	int n,i,x,y,sum=1<<30,a,b;
	scanf("%d",&n);
	for(i=1;i<=3;i++){
		scanf("%d%d",&x,&y);
		if(x!=0){
			a=int(1.0*n/x+0.9999999);
			b=a*y;
			if(b<sum)
				sum=b;
		}
	}
	printf("%d",sum);
	return 0;
}

 

 

 

 

 

 

回文日期

 

 

 

题目描述

 

 

 

 

 

在日常生活中,通过年、月、日这三个要素可以表示出一个唯一确定的日期。

牛牛习惯用8位数字表示一个日期,其中,前4位代表年份,接下来2位代表月 份,最后2位代表日期。显然:一个日期只有一种表示方法,而两个不同的日期的表 示方法不会相同。

牛牛认为,一个日期是回文的,当且仅当表示这个日期的8位数字是回文的。现 在,牛牛想知道:在他指定的两个日期之间包含这两个日期本身),有多少个真实存 在的日期是回文的。

一个8位数字是回文的,当且仅当对于所有的i ( 1 <=i<= 8 )从左向右数的第i个 数字和第9-i个数字(即从右向左数的第i个数字)是相同的。

例如:

•对于2016年11月19日,用8位数字20161119表示,它不是回文的。

•对于2010年1月2日,用8位数字20100102表示,它是回文的。

•对于2010年10月2日,用8位数字20101002表示,它不是回文的。

每一年中都有12个月份:

其中,1、3、5、7、8、10、12月每个月有31天;4、6、9、11月每个月有30天;而对于2月,闰年时有29天,平年时有28天。

一个年份是闰年当且仅当它满足下列两种情况其中的一种:

1.这个年份是4的整数倍,但不是100的整数倍;

2.这个年份是400的整数倍。

例如:

•以下几个年份都是闰年:2000、2012、2016。

•以下几个年份是平年:1900、2011、2014。

输入格式:

输入包括两行,每行包括一个8位数字。第一行表示牛牛指定的起始日期。第二行表示牛牛指定的终止日期。保证date_i和都是真实存在的日期,且年份部分一定为4位数字,且首位数字不为0。

保证date1 —定不晚于date2。

输出格式:

输出一行,包含一个整数,表示在date1和date2之间,有多少个日期是回文的。

样例1输入:

20110101

20111231

样例1输出:

1

 

样例2输入:

 

20000101

 

20101231

 

样例2输出:

2

 

 

【样例说明】

对于样例1,符合条件的日期是20111102。

对于样例2,符合条件的日期是20011002和20100102。

【子任务】

对于60%的数据,满足date1 = date2。

分析:
最开始觉得是一道很坑的题目,就只判断了date1=date2的情况,后来发现可以直接枚举年数,结果忘了判断闰年,

可能要错一个点,要是考试时把“28”写成“29”就好了。。。(希望数据水一点)

 

#include<cstdio>
#include<cstring>
int mon[15]={0,31,28,31,30,31,30,31,31,30,31,30,31};//就是这里
int main()
{
	char a[15],b[15];
	int i,j,f,sf,x,y,z,w,month,day,sum=0;
	scanf("%s\n%s",a,b);
	f=0;
	for(i=0;i<8;i++){
		if(a[i]!=b[i]){
			f=1;
			break;
		}
	}
	if(f==0){
		sf=0;
		for(i=0;i<8;i++){
			if(a[i]!=a[7-i]){
				sf=1;
				break;
			}
		}
		if(sf==0){
			printf("1");
			return 0;
		}
		else{
			printf("0");
			return 0;
		}
	}
	else{
		x=1000*(a[0]-48)+100*(a[1]-48)+10*(a[2]-48)+a[3]-48;
		z=1000*(a[4]-48)+100*(a[5]-48)+10*(a[6]-48)+a[7]-48;
		y=1000*(b[0]-48)+100*(b[1]-48)+10*(b[2]-48)+b[3]-48;
		w=1000*(b[4]-48)+100*(b[5]-48)+10*(b[6]-48)+b[7]-48;
		for(i=x;i<=y;i++){
			if(i%10<2){
				month=i%10*10+i/10%10;
				day=i/100%10*10+i/1000%10;
				if(month<=12){
					if(mon[month]>=day){
						if(i==x){
							if(100*month+day>=z)
								sum++;
						}
						else if(i==y){
							if(100*month+day<=w)
								sum++;
						}
						else sum++;
					}
				}
			}
		}
		printf("%d",sum);
	}
}

 

 

海港

题目描述

小K是一个海港的海关工作人员,每天都有许多船只到达海港,船上通常有很多来自不同国家的乘客。

小K对这些到达海港的船只非常感兴趣,他按照时间记录下了到达海港的每一艘船只情况;对于第i艘到达的船,他记录了这艘船到达的时间ti (单位:秒),船上的乘 客数星ki,以及每名乘客的国籍 x(i,1), x(i,2),…,x(i,k);。

小K统计了n艘船的信息,希望你帮忙计算出以每一艘船到达时间为止的24小时(24小时=86400秒)内所有乘船到达的乘客来自多少个不同的国家。

形式化地讲,你需要计算n条信息。对于输出的第i条信息,你需要统计满足 ti - 86400 < tp <= ti的船只p,在所有的x(p,j)中,总共有多少个不同的数。

样例1输入

3

1 4 4 1 2 2

2 2 2 3

10 1 3

样例1输出:

3

4

4

 

 

 

样例2输入:

4

1 4 1 2 2 3

3 2 2 3

86401 2 3 4

86402 1 5

 

样例2输出:

3

3

3

4

【样例一说明】

第一艘船在第1秒到达海港,最近24小时到达的船是第一艘船,共有4个乘客,分别是来自国家4,1,2,2,共来自3个不同的国家;

第二艘船在第2秒到达海港,最近24小时到达的船是第一艘船和第二艘船,共有 4+2=6个乘客,分别是来自国家4,1,2,2,2,3,共来自4个不同的国家;

第三艘船在第10秒到达海港,最近24小时到达的船是第一艘船、第二艘船和第三艘船,共有4+2+1=7个乘客,分别是来自国家4,1,2,2,2,3,3,共来自4个不同的国家。

【样例二说明】

第一艘船在第1秒到达海港,最近24小时到达的船是第一艘船,共有4个乘客,分别是来自国家1,2,2,3,共来自3个不同的国家。

第二艘船在第3秒到达海港,最近24小时到达的船是第一艘船和第二艘船,共有4+2=6个乘客,分别是来自国家1,2,2,3,2,3,共来自3个不同的国家。

第三艘船在第86401秒到达海港,最近24小时到达的船是第二艘船和第三艘船,共有2+2=4个乘客,分别是来自国家2,3,3,4,共来自3个不同的国家。

第四艘船在第86402秒到达海港,最近24小时到达的船是第二艘船、第三艘船和第四艘船,共有2+2+1=5个乘客,分别是来自国家2,3,3,4,5,共来自4个不同的国家。

分析:
在考试的时候,觉得这道题很坑,结果考完之后才知道是一道水题。

这道题既容易超时,也容易爆内存,最好的方法就是在原来的基础上进行统计。

用一个结构体队列来存一个人的国籍和到达时间,再用一个头指针来判断前面的人到达时间是否超过24小时。

结果我在考试的时候,是用一个vis数组来判重,每次输入一条船,就进行一次判重,最后就超时了。。。

AC代码:

#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
struct node{
    int x,time;
}o,t;
queue <node>a;
int v[100005];
int main()
{
	int i,m,j,n,k,s=0;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        scanf("%d%d",&t.time,&m);
        for(j=1;j<=m;j++){
			scanf("%d",&t.x);
            a.push(t);
            v[t.x]++;
            k=max(k,t.x);
            if(v[t.x]==1)
                s++;
        }
		o=a.front();
		while(t.time-o.time>=86400){
			a.pop();
			v[o.x]--;
			if(!v[o.x])
				s--;
			o=a.front();
		}
		printf("%d\n",s);
    }
}

 

 

 

 

 

 

魔法阵

样例1输入

30 8

1

24

7

28

5

29

26

24

样例1输出

4 0 0 0

0 0 1 0

0 2 0 0

0 0 1 1

1 3 0 0

0 0 0 2

0 0 2 2

0 0 1 0

 

【样例解释1】

共有5个魔法阵,分别为:

物品1,3,7,6,其魔法值分别为1,7,26,29;

物品1,5,2,7,其魔法值分别为1,5,24,26;

物品1,5,7,4,其魔法值分别为1,5,26,28;

物品1,5,8,7,其魔法值分别为1,5,24,26;

物品5,3,4,6,其魔法值分别为5,7,28,29。

以物品5为例,它作为A物品出现了1次,作为B物品出现了3次,没有作为C物品或者D物品出现,所以这一行输出的四个数依次为1,3,0,0。

此外,如果我们将输出看作一个m行4列的矩阵,那么每一列上的m个数之和都应等于魔法阵的总数。所以,如果你的输出不满足这个性质,那么这个输出一定不正确。你可以通过这个性质在一定程度上检查你的输出的正确性。

样例2输入

15 15

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

样例2输出

5 0 0 0

4 0 0 0

3 5 0 0

2 4 0 0

1 3 0 0

0 2 0 0

0 1 0 0

0 0 0 0

0 0 0 0

0 0 1 0

0 0 2 1

0 0 3 2

0 0 4 3

0 0 5 4

0 0 0 5

 

【子任务】

每个测试点的详细数据范围见下表

 

分析:

一看这道题,就觉得是一道很水的题,但是看了数据范围就发现这道题很坑,虽然正解是用枚举,但是枚举是有

技巧的。然而............在考试的时候,我用了4个for循环,超时了一堆点。

听说正解是用2个for循环,但是我现在还没有弄明白用2个for循环的思路,如果有哪位大佬知道,请在评论里面说

一下。

 

 

 

 

 

二、考后心得

经过了这一次NOIP的考试,我觉得NOIP不会考太难的算法,大部分的题目都是考(思维能力+一些简单算法),

只有后面的3题或4题比较难以外,其它的题目都比较正常,但是在考试的时候一定要仔细,有时候数据很坑,

但是样例很简单,你测样例就测不出程序的BUG,所以你就要多编几组特殊数据,尽量卡爆自己的程序,

这样你就可以找出程序的漏洞,从而改进自己的程序,

如果你发现自己的程序在测极端数据时会超时,就想一下其它的方法,比如说第3题,我没有在原来的基础上进行

统计,就超时了。

一些涉及到思维难度的题目,比如说第4题,如果你实在想不出来改进的思路,就去检查一下前面的题,保证自己

在前面的题目上不丢分。

以上就是我对NOIP考试的心得。

 

 

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值