您的位置:首页 > 其它

【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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: