您的位置:首页 > 编程语言 > C语言/C++

NOIP2017普及组复赛解题报告

2017-12-11 16:59 866 查看
这次考试在衢州二中,这里地形太复杂了,离开考前3分钟才找到考场。无语·········所以一开考就没有好心情。这次的题目相对来以往的前几道题比较简单,但最后一道题比较难,考场上只想出来了50分的代码。

时间限制:1s 内存限制:256M

第一题:成绩 score

题目

AC记录

超级水题,NOIP史上最简单的题没有之一,只要c++如果入门的都会做,普通的运算符操作

难度:☆☆☆☆☆ (入门难度)

民间数据:100分

官方得分:100分

#include<bits/stdc++.h>
using namespace std;
int a,b,c;
int ans;
int main()
{
freopen ("score.in","r",stdin);
freopen ("score.out","w",stdout);
scanf ("%d %d %d",&a,&b,&c);
ans=a/5+b/10*3+c/2;
printf ("%d",ans);
return 0;
}


这道题对于c++的选手有一个无法避免的误差,就是使用浮点数(float || double)是直接*0.3会出现t.9999999999········的情况。e.g. :10.0*0.3=2.9999999·····

这导致一些选手出现 printf (”%d”,int (ans))使结果少一,60分

第二题:图书管理员 librarian

题目

AC记录

这道题其实也不难,暴力的时间复杂度也只有O(n*q)==O(1000000),而且图书编码与需求码都用 int 存的下,唯一的难点就是判断末尾是否相等,需要一定的代码能力

难度:★☆☆☆☆ (普及-)

难点:check 处理

民间数据:100分

官方成绩:100分

#include<bits/stdc++.h>
using namespace std;
int n,q;
int a[1010];
int main()
{
freopen ("librarian.in","r",stdin);
freopen ("librarian.out","w",stdout);
scanf ("%d%d",&n,&q);
for (int i=1;i<=n;i++)
scanf ("%d",&a[i]);
sort (a+1,a+n+1);      //c++ STL
for (int i=1;i<=q;i++)
{
int l,x;
bool flag=0;
scanf ("%d %d",&l,&x);
int t=pow (10,l);          //计算t 即末尾0的个数
for (int i=1;i<=n;i++)
if ((a[i]-x)%t==0)   //重点:若x是a[i]的位数,那么(a[i]-x)%t==0
{
flag=1;
printf ("%d\n",a[i]);
break;
}
if (!flag)
printf ("-1\n");
}
return 0;
}


这道题可以有变式,就是将字典编码长度与查询码长度最大为100(注意是长度,不是数值),这样对于排序就有点难了。

第三题:棋盘 chess

题目

AC记录

难度:★★☆☆☆ (普及刚好)

民间数据:100分

官方数据:100分

这道题代码量还是挺大的,考试时用记忆化搜索做的,但据说最好的解决方案是广度优先搜索,但我的方法也AC了,记忆化搜索相对来说好写一点但是,需要很细心,在考场上

#include<bits/stdc++.h>
using namespace std;
int minn[110][110][2];
int n,m,ans=10000;
int a[110][110];
void DFS (int x,int y,int cos,bool way,int c)
{
if (minn[x][y][c]<=cos)
return;
minn[x][y][c]=cos;
if (x==m&&y==m)
{
ans=min (ans,cos);
return;
}
if (c==a[x+1][y])
DFS (x+1,y,cos,1,c);
else if (a[x+1][y]!=-1)
DFS (x+1,y,cos+1,1,a[x+1][y]);
else if (way)
{
if (c==1)
{
DFS (x+1,y,cos+2,0,1);
DFS (x+1,y,cos+<
4000
span class="hljs-number">3,0,0);
}
else
{
DFS (x+1,y,cos+2,0,0);
DFS (x+1,y,cos+3,0,1);
}
}

if (c==a[x-1][y])
DFS (x-1,y,cos,1,c);
else if (a[x-1][y]!=-1)
DFS (x-1,y,cos+1,1,a[x-1][y]);
else if (way)
{
if (c==1)
{
DFS (x-1,y,cos+2,0,1);
DFS (x-1,y,cos+3,0,0);
}
else
{
DFS (x-1,y,cos+2,0,0);
DFS (x-1,y,cos+3,0,1);
}
}

if (c==a[x][y+1])
DFS (x,y+1,cos,1,c);
else if (a[x][y+1]!=-1)
DFS (x,y+1,cos+1,1,a[x][y+1]);
else if (way)
{
if (c==1)
{
DFS (x,y+1,cos+2,0,1);
DFS (x,y+1,cos+3,0,0);
}
else
{
DFS (x,y+1,cos+2,0,0);
DFS (x,y+1,cos+3,0,1);
}
}
if (c==a[x][y-1])
DFS (x,y-1,cos,1,c);
else if (a[x][y-1]!=-1)
DFS (x,y-1,cos+1,1,a[x][y-1]);
else if (way)
{
if (c==1)
{
DFS (x,y-1,cos+2,0,1);
DFS (x,y-1,cos+3,0,0);
}
else
{
DFS (x,y-1,cos+2,0,0);
DFS (x,y-1,cos+3,0,1);
}
}
}
int main()
{
freopen ("chess.in","r",stdin);
freopen ("chess.out","w",stdout);
memset (minn,-1,sizeof (minn));
memset (a,-1,sizeof (a));
scanf ("%d%d",&m,&n);
for (int i=1;i<=n;i++)
{
int x,y,c;
scanf ("%d%d%d",&x,&y,&c);
a[x][y]=c;
}
for (int i=1;i<=m;i++)
for (int j=1;j<=m;j++)
{
minn[i][j][0]=10000;
minn[i][j][1]=10000;
}
DFS (1,1,0,1,a[1][1]);
if (ans==10000)
{
printf ("-1");
return 0;
}
printf ("%d",ans);
return 0;
}


第四题:跳房子 jump

题目

AC记录

50分记录

20分记录

第一眼看到数据大小就想到了二分答案,然后在check函数中就想到了用动态规划(DP)来做,但这是O(N^2)的算法肯定会超时,但得50分已经可以了,但二分写错了,这是最恶心的地方,只得了20分

标准程序是用二分答案+单调队列来做的,略微超纲了,那是提高组的算法,是比较难理解的

难度:★★★★☆ (提高+)

民间数据:20分

官方得分:20分

20分代码

#include<bits/stdc++.h>
using namespace std;
int n,d,k;
int x[500010],s[500010];
int sum=0,ans;
bool check (int u)
{
int f[500010];
memset (f,0,sizeof (f));
f[0]=0;
int ans=-1000000010;
for (int i=0;i<=n;i++)
{
int l1=x[i]+d-u;
if (l1<=x[i])
l1=x[i]+1;
int r1=x[i]+d+u;
if (r1>=x
)
r1=x
;
for (int j=i+1;j<=n;j++)
if (x[j]>=l1&&x[j]<=r1)
{
f[j]=max (f[j],f[i]+s[j]);
ans=max (ans,f[j]);
}
}
if (ans>=k)
return 1;
else
return 0;
}
int main()
{
//freopen ("jump.in","r",stdin);
//freopen ("jump.out","w",stdout);
scanf ("%d%d%d",&n,&d,&k);
x[0]=0;
for (int i=1;i<=n;i++)
{
scanf ("%d%d",&x[i],&s[i]);
if (s[i]>0)
sum+=s[i];
}
if (sum<k)
{
printf ("-1");
return 0;
}
int l=0,r=1000000010;
while (l<r)
{
int mid=(l+r)/2;
if (check (mid))
{
r=mid-1;
ans=mid;
}
else
l=mid+1;
}
printf ("%d",ans);
return 0;
}


50分代码

#include<bits/stdc++.h>
using namespace std;
int n,d,k;
int x[500010],s[500010];
int sum=0,ans;
int f[500010];
bool check (int u)
{
memset (f,0,sizeof (f));
f[0]=0;
int ans=-1000000010;
for (int i=0;i<=n;i++)
{
int l1=x[i]+d-u;
if (l1<=x[i])
l1=x[i]+1;
int r1=x[i]+d+u;
if (r1>=x
)
r1=x
;
for (int j=i+1;j<=n;j++)
if (x[j]>=l1&&x[j]<=r1)
{
f[j]=max (f[j],f[i]+s[j]);
ans=max (ans,f[j]);
if (ans>=k)
return 1;
}
}
if (ans>=k)
return 1;
else
return 0;
}
int main()
{
//freopen ("jump.in","r",stdin);
//freopen ("jump.out","w",stdout);
scanf ("%d%d%d",&n,&d,&k);
x[0]=0;
for (int i=1;i<=n;i++)
{
scanf ("%d%d",&x[i],&s[i]);
if (s[i]>0)
sum+=s[i];
}
if (sum<k)
{
printf ("-1");
return 0;
}
int l=0,r=1000000010;
while (l<r)
{
int mid=(l+r)/2;
if (check (mid))
r=mid;
else
l=mid+1;
}
printf ("%d",l);
return 0;
}


AC代码 单调队列

#include<bits/stdc++.h>
using namespace std;
struct node{
int x,v;
}q[500005];
int f[500005];
long long maxx=0;
int n,d,k;
int dis[500005],sc[500005];
bool check (int g)
{
int low=max (1,d-g),high=d+g;
int cur=0,head=0,tail=-1;
memset (f,0,sizeof (f));
for (int i=1;i<=n;i++)
{
for (;cur<i&&dis[cur]<=dis[i]-low;cur++)
{
while (head<=tail&&q[tail].v<f[cur])
tail--;
if (f[cur]!=-0x3f3f3f3f)
q[++tail].v=f[cur],q[tail].x=dis[cur];
}
while (head<=tail&&dis[i]-q[head].x>high)
head++;
f[i]=(head<=tail)?q[head].v+sc[i]:-0x3f3f3f3f;
if (f[i]>=k)
return 1;
}
return 0;
}
int main()
{
scanf ("%d%d%d",&n,&d,&k);
for (int i=1;i<=n;i++)
{
scanf ("%d%d",&dis[i],&sc[i]);
maxx+=max (sc[i],0);
}
if (maxx<k)
{
printf ("-1");
return 0;
}
int l=1,r=dis
;
while (l<r)
{
int mid=(l+r)/2;
if (check (mid))
r=mid;
else
l=mid+1;
}
printf ("%d",l);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++ NOIP2017