【NOIP2016普及组】解题报告 买铅笔 回文日期 海港 魔法阵
2016-11-22 17:48
441 查看
测题网站公示
大家可以测一下,算一下平均分。这是我第一次参加NOIP竞赛。
经过了这次考试,我更加明白了骗分的含义。。。
题目下载链接
cena评测包下载
官方评测数据包
总结
考前做了足够的准备吧,每天复习一下知识点,重做经典的例题什么的~然后考试时觉得自己的状态良好吧,能够编写出符合题意的程序,就是觉得时间不够,没有去一道一道的去编写两个程序对拍。
事实上,我觉得这次考试稍微有一点水,但是我还是有一些题该骗到的分没有被骗到(或者做出来)。
所以测下来才230分。
我觉得我需要再提高的是我的骗分技巧。
题目详解
买铅笔
原题
题目描述
P老师需要去商店买n支铅笔作为小朋友们参加NOIP的礼物。她发现商店一共有3种包装的铅笔,不同包装内的铅笔数量有可能不同,价格也有可能不同。为了公平起见,P老师决定只买同一种包装的铅笔。商店不允许将铅笔的包装拆开,因此P老师可能需要购买超过n支铅笔才够给小朋友们发礼物。
现在P老师想知道,在商店每种包装的数量都足够的情况下,要买够至少n支铅笔最少需要花费多少钱。
输入输出格式
输入格式:输入的第一行包含一个正整数n,表示需要的铅笔数量。
接下来三行,每行用两个正整数描述一种包装的铅笔:其中第一个整数表示这种包装内铅笔的数量,第二个整数表示这种包装的价格。
保证所有的7个数都是不超过10000的正整数。
输出格式:
输出一行一个整数,表示P老师最少需要花费的钱。
输入输出样例
输入样例#1:
57
2 2
50 30
30 27
输出样例#1:
54
输入样例#2:
9998
128 233
128 2333
128 666
输出样例#2:
18407
输入样例#3:
9999
101 1111
1 9999
1111 9999
输出样例#3:
89991
说明
铅笔的三种包装分别是:2支装,价格为2;
50支装,价格为30;
30支装,价格为27。
P老师需要购买至少57支铅笔。
如果她选择购买第一种包装,那么她需要购买29份,共计2x29=58支,需要花费的钱为2x29=58。
实际上,P老师会选择购买第三种包装,这样需要买2份。虽然最后买到的铅笔数量更多了,为30x2=60支,但花费却减少为27x2=54,比第一种少。
对于第二种包装,虽然每支铅笔的价格是最低的,但要够发必须买2份,实际的花费达到了30x2=60,因此P老师也不会选择。
所以最后输出的答案是54。
子任务
子任务会给出部分测试数据的特点。如果你在解决题目中遇到了困难,可以尝试只解决一部分测试数据。
每个测试点的数据规模及特点如下表:
上表中“整倍数”的意义为:若为“K”,表示对应数据所需要的铅笔数量n—定是每种包装铅笔数量的整倍数(这意味着一定可以不用多买铅笔)。
分析
初步鉴定:水题。大概得分:100
表示只要把每一种笔都试一下,一直买到大于等于n就行了(因为题目中说了n和两个数都为正整数,所以不用判断为0的情况),从三个情况中选择最小的花费就行了。
源代码
我的代码提示:请登录后进行操作。
#include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int n,ans=0x7fffffff; struct pencil{ int a; int b; }p[4]; int main() { //freopen("pencil.in","r",stdin); //freopen("pencil.out","w",stdout);//文件的读入输出 cin>>n; for(int i=1;i<=3;i++) cin>>p[i].a>>p[i].b; for(int i=1;i<=3;i++) if(int((n*1.0)/p[i].a+0.99999)*p[i].b<ans) ans=int((n*1.0)/p[i].a+0.99999)*p[i].b;//无限加(因为所有数都为正整数) cout<<ans; //fclose(stdin); //fclose(stdout);//关闭文件 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天。
一个年份是闰年当且仅当它满足下列两种情况其中的一种:
这个年份是4的整数倍,但不是100的整数倍;
这个年份是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。
分析
初步鉴定:有点坑(考虑每个月的方面,和闰年的2月份的情况),但是应该得满分。大概得分:60
这道题,我就是用的最笨的方法,就是用3个for循环把每一天的情况都列举出来,可是只过了60%,也就是题目中说的当两个日期相等的情况,幸好,至少没有拿0分。
这道题应该直接列举年份,出现与其相对的日期是否合法就行了。
源代码
我的代码提示:请登录后进行操作。
#include<cstdio> #include<iostream> using namespace std; int day[13]={0,31,29,31,30,31,30,31,31,30,31,30,31}; int A,B,ans,maxy,miny,maxm,minm,maxd,mind; int check(int m,int d){ int y; y=(d%10)*1000+(d/10)*100+(m%10)*10+(m/10); if(y>miny&&y<maxy) return 1; if(y==miny){ if(m>minm) return 1; if(m==minm&&d>=mind) return 1; } if(y==maxy){ if(m<maxm) return 1; if(m==maxm&&d<=maxd) return 1; } return 0; } int main() { ans=0; cin>>A>>B; maxy=B/10000,maxm=(B%10000)/100,maxd=B%100; miny=A/10000,minm=(A%10000)/100,mind=A%100; for(int i=1;i<=12;i++) for(int j=1;j<=day[i];j++) ans+=check(i,j); cout<<ans; }
海港
原题
题目描述
小K是一个海港的海关工作人员,每天都有许多船只到达海港,船上通常有很多来自不同国家的乘客。小K对这些到达海港的船只非常感兴趣,他按照时间记录下了到达海港的每一艘船只情况;对于第i艘到达的船,他记录了这艘船到达的时间ti(单位:秒),船上的乘客数量ki,以及每名乘客的国籍xi,1,xi,2,…,xi,k。
小K统计了n艘船的信息,希望你帮忙计算出以每一艘船到达时间为止的24小时(24小时=86400秒)内所有乘船到达的乘客来自多少个不同的国家。
形式化地讲,你需要计算n条信息。对于输出的第i条信息,你需要统计满足ti−86400<tp≤ti的船只p,在所有的xp,j中,总共有多少个不同的数。
输入输出格式
输入格式:第一行输入一个正整数n,表示小K统计了n艘船的信息。
接下来n行,每行描述一艘船的信息:前两个整数ti和ki分别表示这艘船到达海港的时间和船上的乘客数量,接下来ki个整数xi,j表示船上乘客的国7。
保证输入的ti是递增的,单位是秒;表示从小K第一次上班开始计时,这艘船在第ti秒到达海港。
保证1≤n≤105,ki≥1,∑ki≤3×105,1≤ti−1≤ti≤109。
其中表示所有的ki的和。
输出格式:
输出n行,第i行输出一个整数表示第i艘船到达后的统计信息。
输入输出样例
输入样例#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第一艘船在第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个不同 的国家。
样例解释2
第一艘船在第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个不同的国家。
分析
初步鉴定:一般般大概得分:70
这道题,听他们说要用队列vector来做,我只是用最笨的方法int数组+for循环一道判断在不在86400秒内,如果在就累加起来。所以会超时,幸好对于70%的测试点,1≤n≤1000,∑ki≤3000;1≤xi,j≤1000;1≤ti≤109否则就0分了。
源代码
我的代码提示:请登录后进行操作。
#include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<cstdlib> #include<cstring> #include<queue> using namespace std; int x[100001],n,sum; struct node { int t,p; }; queue <node> h; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { int t,p; scanf("%d%d",&t,&p); for(int j=1;j<=p;j++){ node now; int g; scanf("%d",&g); now.t=t;now.p=g; h.push(now); x[g]++; if(x[g]==1) sum++; } node a=h.front(); node now=h.back(); while(a.t<=now.t-86400) { x[a.p]--;if(x[a.p]==0) sum--; h.pop(); a=h.front(); } printf("%d\n",sum); } }
魔法阵
原题
题目描述
六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法能量。大魔法师有m个魔法物品,编号分别为1,2,…,m。每个物品具有一个魔法值,我们用xi表示编号为i的物品的魔法值。每个魔法值xi是不超过n的正整数,可能有多个物品的魔法值相同。
大魔法师认为,当且仅当四个编号为a,b,c,d的魔法物品满足xa<xb<xc<xd,xb−xa=2(xd−xc),并且xb−xa<(xc−xb)/3时,这四个魔法物品形成了一个魔法阵,他称这四个魔法物品分别为这个魔法阵的A物品,B物品,C物品,D物品。
现在,大魔法师想要知道,对于每个魔法物品,作为某个魔法阵的A物品出现的次数,作为B物品的次数,作为C物品的次数,和作为D物品的次数。
输入输出格式
输入格式:输入文件的第一行包含两个空格隔开的正整数n和m。
接下来m行,每行一个正整数,第i+1行的正整数表示Xi,即编号为i的物品的魔法值。
保证1≤n≤15000,1≤m≤40000,1≤xi≤n。每个xi是分别在合法范围内等概率随机生成的。
输出格式:
共输出m行,每行四个整数。第i行的四个整数依次表示编号为i的物品作 为A,B,C,D物品分别出现的次数。
保证标准输出中的每个数都不会超过109。
每行相邻的两个数之间用恰好一个空格隔开。
输入输出样例
输入样例#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
输入样例#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
说明
样例解释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个数之和都应等于魔法阵的总数。所以,如果你的输出不满足这个性质,那么这个输出一定不正确。你可以通过这个性质在一定程度上检查你的输出的正确性。
分析
初步鉴定:坑爹大概得分:0
这道题可谓是最终的压轴题,这道题我在考试时就是用4个for循环来做的,想多骗一点分,结果一分都木有骗掉,香菇蓝瘦/(ㄒoㄒ)/~~
于是乎,并没有骗到一分XAX,在考试时我可用了40分钟来做啊(好吧,某种意义叫骗分吧)!
源代码
我的代码提示:请登录后进行操作。
#include<cstdio> #include<iostream> using namespace std; int a[15005],b[15005],c[15005],d[15005],w[15005]; int h[40005]; int f[15005]; int n,m,k,t,x,y,z,p,q; int main() { cin>>n>>m; for(int i=1;i<=m;i++){ cin>>h[i]; w[h[i]]++; } for(int i=1;i<=n/9;i++){ x=1+9*i;y=0; for(int j=2+9*i;j<=n;j++){ y=y+w[(j-x)]*w[j-x+i+i]; d[j]=d[j]+y*w[j-i]; c[j-i]=c[j-i]+y*w[j]; } x=8*i+1;y=0; for(int j=n-9*i-1;j>=1;j--){ y=y+w[j+x]*w[j+x+i]; a[j]=a[j]+y*w[j+i+i]; b[j+i+i]=b[j+i+i]+y*w[j]; } } for(int i=1;i<=m;i++) cout<<a[h[i]]<<" "<<b[h[i]]<<" "<<c[h[i]]<<" "<<d[h[i]]<<endl; }
相关文章推荐
- NOIP2016普及组T3海港解题报告
- c++回文日期【NOIP2016普及组】解题报告
- 【原创】【NOIP2016普及组】回文日期
- NOIP2016普及组第二题——回文日期
- [NOIP2016普及] 回文日期
- NOIP2016普及组复赛解题报告
- NOIP2016普及组复赛解题报告
- NOIP2016-普及组复赛-第2题-回文日期
- NOIP2016普及组复赛第二题60分程序加题解pascal大神求帮忙!!!———回文日期
- 【NOIP2016普及组】复赛——回文日期
- LuoguP2822[NOIP2016] 组合数问题 解题报告【组合数取模+矩阵前缀和】
- NOIP2012普及组 (四年后的)解题报告 -SilverN
- NOIP2008 普及组T4 立体图 解题报告-S.B.S.(施工未完成)
- NOIP2016普及组第四题——魔法阵
- [NOIP2016普及] 买铅笔
- 【NOIP普及组】2016模拟考试(10.29)——海港的船只
- NOIP2016普及组复赛买铅笔
- NOIP2016普及组第一题——买铅笔
- NOIP2016普及组第四题魔法阵解说+水法
- 【NOIP2016普及组复赛】魔法阵