2017NOIP考后总结

NOIP瞬闪而过,除了那孤零零的 200 这个数字意外,似乎没有什么痕迹能够向我证明他曾经来过。


从初学C++的激动与陌生到如今面对成绩的,中间也多多少少经历了一些值得
怀念的地方……哎,不说了。

错因分析


整体来说,我一二题都分别得了满分,但是三四题出现了严重的错误:没有打cstdio!哎,只剩叹息。

(1) score

题目大意:
输入A,B,C(A,B,C<=100),计算A×20%+B×30%+C× 50%的结果。

吐槽:
没错,NOIP延续了一直以来的A题送分的操作,看着这个题目我就想笑,直接上代码。

#include<cstdio>
int a,b,c;
int main()
{
    scanf("%d%d%d",&a,&b,&c);
    a/=5;
    b=b/10*3;
    c/=2;
    printf("%d",a/5+b/10*3+c/2);
}
(2) librarian

题目大意:
输入一个n和q,接着有n个图书编码,然后读入q个需求码的长度以及需求码。若一个图书编码以读者的需求码结尾,输出此书的图书编码。要求:使图书编码尽量小;若找不到,输出-1.

数据要求:
n,q<=1,000,图书编码<1,00,000,000

吐槽:
考完下来一阵恐慌:同去的同学say 数据有前导0!!!

心态崩

结果只是他自己脑子发热了。呼,虚惊一场。不过这也说明了我读题审题也并不严谨,没有十足的把握。话说回来,这道题还是蛮简单的,直接用int存,再加个pow函数枚举取余,轻松满分。来人,上代码!

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
long long book[1005],len[1005],want[1005];
bool f;
int main()
{
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
        scanf("%lld",&book[i]);
    for(int i=1;i<=q;i++)
        scanf("%lld%lld",&len[i],&want[i]);
    sort(book+1,book+1+n);
    for(int i=1;i<=q;i++)
    {
        f=0;
        long long now=pow(10,len[i]);
        for(int j=1;j<=n;j++)
            if(book[j]%now==want[i])
                {printf("%lld\n",book[j]);f=1;break;}
        if(f==0)printf("-1\n");
    }
    return 0;
}

哦,为了保险我还用了一个long long,浪费!!!

(3) Chess

题目大意:
有一个m × m的棋盘,棋盘上每一个格子可能是红色、黄色或没有任何颜色的。你现在要从棋盘的最左上角走到棋盘的最右下角。任何一个时刻,你所站在的位置必须是有颜色的(不能是无色的),你只能向上、下、左、右四个方向前进。当你从一个格子走向另一个格子时,如果两个格子的颜色相同,那你不需要花费金币;如果不同,则你需要花费1 个金币。另外,你可以花费2 个金币施展魔法让下一个无色格子暂时变为你指定的颜色。但这个魔法不能连续使用,而且这个魔法的持续时间很短,也就是说,如果你使用了这个魔法,走到了这个暂时有颜色的格子上,你就不能继续使用魔法;只有当你离开这个位置,走到一个本来就有颜色的格子上的时候,你才能继续使用这个魔法,而当你离开了这个位置(施展魔法使得变为有颜色的格子)时,这个格子恢复为无色。现在你要从棋盘的最左上角,走到棋盘的最右下角,求花费的最少金币是多少?
(太复杂了,不好概括,具体请参照:)
https://wenku.baidu.com/view/e3232b1eac02de80d4d8d15abe23482fb4da02e9.html

吐糟:
很明显,这是一道搜索题,当然,简单的搜索自然是不能过的,只要稍稍加一个记忆化就行了。BUT,考场上的我很明显并没有想起这一点,就用了一堆繁纷复杂的if
见下:

#include<iostream>
#include<cstdio>
using namespace std;
int fxa[1005][1005];
int m,n;
void love(int x,int y,int ans,bool f)
{
    if(x==m&&y==m) {printf("%d",ans);return;}
    if(f==0)
    {
        if(fxa[x+1][y]==fxa[x][y]&&x+1<=m) love(x+1,y,ans,0);
        else if(fxa[x][y+1]==fxa[x][y]&&y+1<=m) love(x,y+1,ans,0);
        else if((fxa[x+1][y]==1||fxa[x+1][y]==2)&&x+1<=m) love(x+1,y,ans+1,0);
        else if((fxa[x][y+1]==1||fxa[x][y+1]==2)&&y+1<=m) love(x,y+1,ans+1,0);
        else if(x+1<=m) fxa[x+1][y]=fxa[x][y],fxa[x][y]=0,love(x+1,y,ans+2,1);
        else if(y+1<=m)fxa[x][y+1]=fxa[x][y],fxa[x][y]=0,love(x,y+1,ans+2,1);
    }
    else
    {
        if(fxa[x+1][y]==0&&fxa[x-1][y]==0&&fxa[x][y+1]==0&&fxa[x][y-1]==0)
        {
            printf("-1");
            return;
        }
        if(fxa[x+1][y]==fxa[x][y]&&x+1<=m) love(x+1,y,ans,0);
        else if(fxa[x][y+1]==fxa[x][y]&&y+1<=m) love(x,y+1,ans,0);
        else if((fxa[x+1][y]==1||fxa[x+1][y]==2)&&x+1<=m) love(x+1,y,ans+1,0);
        else if((fxa[x][y+1]==1||fxa[x][y+1]==2)&&y+1<=m) love(x,y+1,ans+1,0);
    }
}

自测竟然神奇的过了25?不可思议。我的思想就是只考虑下和右边(其实就是贪心好吧),然后用了我的 打了一长串的if
好,下面是正解了:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int m,n;
int fxa[1005][1005],way[4][2]={{1,0},{0,1},{-1,0},{0,-1}},map[1005][1005][3];
void LOVEer(int x,int y,int color,int flag,int ans)
{
    //printf("%d:%d\n",x,y);
    if(map[x][y][color]==-1||map[x][y][color]>ans)
        map[x][y][color]=ans;
    else return;
    if(x==m&&y==m)return;
    for(int i=0;i<4;i++)
    {
        int next_x=x+way[i][0],next_y=y+way[i][1];
        if(next_x>0&&next_y>0&&next_x<=m&&next_y<=m)
        {
            if(fxa[next_x][next_y]==color)
                LOVEer(next_x,next_y,color,0,ans);
            if(fxa[next_x][next_y]==3-color)
                LOVEer(next_x,next_y,3-color,0,ans+1);
            else if(flag==0)
                LOVEer(next_x,next_y,color,1,ans+2);
        }
    }
}
int main()
{
    memset(map,-1,sizeof(map));
    scanf("%d%d",&m,&n);
    int x,y,color;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&x,&y,&color);
        fxa[x][y]=color+1;
    }
    LOVEer(1,1,fxa[1][1],0,0);
    int minn=0x3f3f3f3f;
    for(int i=1;i<=2;i++)
        if(map[m][m][i]!=-1)
            minn=min(map[m][m][i],minn);
    if(minn==0x3f3f3f3f)
        printf("-1");
    else
        printf("%d",minn);
}

其实这道题想来也是非常水,用一个三维数组储存行列和是否使用过魔法,这样自然很浪费但是易于理解对吧。我这算法也有提升的空间,毕竟运行时间有107ms(某dalao写了耗时1的代码!!!)具体的改进方案也不说了,读者自行思考。

(4) Jump

题目大意:
https://wenku.baidu.com/view/e3232b1eac02de80d4d8d15abe23482fb4da02e9.html

吐槽:
不想说什么了,考试的时候没有任何思路,就打了一个-1以为能骗10分(结果连cstdio都没打!!!)
哦,至今我都没自己想出来怎么做,有兴趣的自己看我们学校满分的dalao的代码:

//if I didn't AK this,there is no doubt that something there is really disturbing and even disgusting
//上面是dalao原句
#include<cstdio>
#include<cstring>
#include<deque>
#include<ctime>
#include<algorithm>
#define maxn 500005
using namespace std;

int n,d,k;
int dis[maxn],w[maxn],dp[maxn];

deque<int>q;

bool check(int s){
    memset(dp,-0x3f,sizeof dp);
    dp[0]=0;
    while(!q.empty())q.pop_front();
    for(int i=1,j=0;i<=n;i++)
    {
        for(;dis[i]-dis[j]>=max(1,d-s);j++)
        {
            while(!q.empty() && dp[j]>=dp[q.back()]) q.pop_back();
            q.push_back(j);
        }
        while(!q.empty() && dis[i]-dis[q.front()]>d+s)
            q.pop_front();

        if(!q.empty()) dp[i]=dp[q.front()]+w[i];
        else dp[i]=-0x3f3f3f3f;
        if(dp[i]>=k) return 1;
    }
    return 0;
}

int main(){
    freopen("jump.in","r",stdin);
    freopen("jump.out","w",stdout);
    int Max=0;
    long long sum=0;
    scanf("%d%d%d",&n,&d,&k);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&dis[i],&w[i]);
        if(w[i]>0) sum+=w[i];
        Max=max(dis[i]-dis[i-1],Max);
    }

    if(sum<k){
        printf("-1");   
        return 0;
    }

    int L=0,R=max(d,Max),Mid;
    while(L<R){
        Mid=(L+R)>>1;
        if(check(Mid)) R=Mid;
        else L=Mid+1;
    }

    if(!check(L)) L=-1;
    printf("%d",L);
}

考试总结

总的来说,这次考试还是没有完完全全的发挥出我的实力,但是,这都是生活,都是经历对吧。
再说,当太阳在寂静的石板上平铺光辉的那一刻,地上的每一个坎坷都被照耀地灿烂。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值