【洛谷搬运】NOIP2018 退役记

本文记录了作者参加2018年全国青少年信息学奥林匹克联赛(NOIP)的经历,从初次接触C++到参赛准备,再到比赛当天的体验。作者分享了对每道题目的理解和解题思路,以及比赛后的反思和得分分析。文章展示了作者从新手到有一定水平的编程竞赛选手的成长过程。
摘要由CSDN通过智能技术生成

 NOIP2018 退役记

原写于2018.11.17 搬运于2021.8.12

权当留个纪念&体验一下在CSDN写博客

以下代码全为考场代码

第一次参加NOIP,也是最后一次参加NOIP。

2017.4

第一次使用C++,还用的是5.4.1辣鸡版本。

第一次接触这个东西,感觉挺有意思的。但是又好难懂啊。

第一个程序写的什么已经不记得了,只记得当时一个编译就搞了好久。还以为编译通过了程序就写对了。

后面慢慢熟悉了一点,会写if语句和for语句了。还不会打印字母塔。

 2017.6.13~暑假

中考,离校,南开十日游,尴尬回CQEW,一堆杂七杂八的事情。

当时想的是学数学竞赛,然后能考多少考多少。

2017.11.10 NOIP2017

当时还在数竞苟着,班上学OI的去参加了NOIP2017,结果最高分60。。。

觉得OI好难还是数学友好。

2017.11.??

自己也记不清具体时间了,反正是在半期考试过后。

当时钻石教练XQZ莫名其妙来了我们学校?!

然后在班上刮起了一股“信奥风”。(就是班主任觉得学OI得一等奖概率大些,并且学了之后还可以回来再学一门竞赛)

于是班级rk1 NH3Pig、数竞dalao Jhin 、物竞dalao BeerBottle 纷纷转学OI

突然知道我舅舅是CQ赛区的特派员?!(一脸懵逼)

于是在家长+老师+特派员的劝导下,转学OI。

 2017.12.1~2018.11.9

 从蒟蒻到萌新


 重点来了

 Day -1

从娄底回CQ,高铁站发现自己的身份证消磁了?!

差点留在HN,还好后面用订票号取到了票。

回来的路上有点慌,不是怕即将到来的NOIP,而是怕回来之后的文化课(翘了一个多月的课)

以至于到高铁站的时候非常感伤。

 Day 0

在机房写一些奇奇怪怪的总结。

下午去试机发现机子并没有安排好?!那还试个鬼哟。(不停暗示:电脑不能单步调试的概率非常小)于是随便找了一台电脑打了KMP等小程序。

看了一些模板,期间和足球团的聊了一下NOIP,发现他们都是初三--哇好羡慕。

自我催眠做得挺好的。

考前发了一条说说,%了校内几位传奇巨佬。

![](

好像没人明白。。。意思是JWJ AK(只是幻想罢了)

 Day 1

一点都不慌?!

密码是飞雪连天,把2看成了‘Z’,吓了一跳。

T1看了一眼,这不是——积木大赛原题吗?!woc,迟迟不敢写代码,虚得一批。

最后10min发现了一个:首尾相连,以为是环,结果样例都不对。果断搭积木!!!

#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;

int gi(){
    char x=getchar();int t=0,fh=1;
    while(x<'0'||x>'9'){if(x=='-')fh=-1;x=getchar();}
    while(x>='0'&&x<='9') {t=t*10+x-'0';x=getchar();}
    return fh*t;
}

int n;
int a[100010];
ll f[100010],ans,maxn;

int main(){
     freopen("road.in","r",stdin);
     freopen("road.out","w",stdout);
    n=gi();
    for(int i=1;i<=n;i++) a[i]=gi();
    ans=a[1];
    for(int i=2;i<=n;i++){
        if(a[i]<a[i-1]) continue;
        else ans+=a[i]-a[i-1];
    }
    printf("%lld\n",ans);
     fclose(stdin);
     fclose(stdout);
    return 0;
}

期望得分:100  Luogu得分:100  实际得分:100

T2 货币系统 

看了题目之后:邮票问题?dfs、dp?数学题?$n≤5$可以直接爆搜枚举所有情况得50分?然后还有三十分可以枚举?

大概11:00左右想到了O(Tnm)复杂度的枚举?!!!

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

int gi(){
    char x=getchar();int t=0,fh=1;
    while(x<'0'||x>'9'){if(x=='-')fh=-1;x=getchar();}
    while(x>='0'&&x<='9') {t=t*10+x-'0';x=getchar();}
    return fh*t;
}

int t,n,m,a[25010],maxn;
int p[110],tp;

bool pd(){
    bool ok[1010];
    memset(ok,0,sizeof(ok));
    int k[10];memset(k,0,sizeof(k));
    if(tp==1){
        for(int i=1;i<=n;i++){
            if(a[i]%p[1]==0) continue;
            else return 0;
        }
        return 1;
    }
    if(tp==2){
        for(k[1]=0;k[1]*p[1]<=maxn;k[1]++){
            for(k[2]=0;k[2]*p[2]+k[1]*p[1]<=maxn;k[2]++){
                ok[k[1]*p[1]+k[2]*p[2]]=1;
            }
        }
        for(int i=1;i<=n;i++){
            if(ok[a[i]]) continue;
            else return 0;
        }
        return 1;
    }
    if(tp==3){
        for(k[1]=0;k[1]*p[1]<=maxn;k[1]++){
            for(k[2]=0;k[2]*p[2]+k[1]*p[1]<=maxn;k[2]++){
                for(k[3]=0;k[3]*p[3]+k[2]*p[2]+k[1]*p[1]<=maxn;k[3]++)
                ok[k[3]*p[3]+k[2]*p[2]+k[1]*p[1]]=1;
            }
        }
        for(int i=1;i<=n;i++){
            if(ok[a[i]]) continue;
            else return 0;
        }
        return 1;
    }
    if(tp==4){
        for(k[1]=0;k[1]*p[1]<=maxn;k[1]++){
            for(k[2]=0;k[2]*p[2]+k[1]*p[1]<=maxn;k[2]++){
                for(k[3]=0;k[3]*p[3]+k[2]*p[2]+k[1]*p[1]<=maxn;k[3]++){
                    for(k[4]=0;k[4]*p[4]+k[3]*p[3]+k[2]*p[2]+k[1]*p[1]<=maxn;k[4]++){
                        ok[k[4]*p[4]+k[3]*p[3]+k[2]*p[2]+k[1]*p[1]]=1;
                    }
                }
            }
        }
        for(int i=1;i<=n;i++){
            if(ok[a[i]]) continue;
            else return 0;
        }
        return 1;
    }
}

void dfs(int now){
    if(now==n+1){
        if(tp==0) return ;
        if(pd()) m=min(m,tp);
        return ;
    }
    if(tp>=m) return ;
    dfs(now+1);
    p[++tp]=a[now];
    dfs(now+1);
    p[tp--]=0;
}

void part1(){
    m=n;dfs(1);
    printf("%d\n",m);
    return ;
}

bool sta[25010],in[25010];

void part2(){
    memset(sta,0,sizeof(sta));
    memset(in,0,sizeof(in));
    for(int i=1;i<=n;i++) in[a[i]]=1,sta[a[i]]=1;
    for(int i=1;i<=maxn;i++){
        if(sta[i]){
            for(int j=i+i;j<=maxn;j+=i) sta[j]=1,in[j]=0;
            for(int j=i+1;j+i<=maxn;j++){
                if(sta[j]){
                    sta[i+j]=1;
                    in[i+j]=0;
                }
            }
        }
    }
    for(int i=1;i<=n;i++){
        if(in[a[i]]) m++;
    }
    printf("%d\n",m);
}

void part3(){
    m=0;
    memset(sta,0,sizeof(sta));
    memset(in,0,sizeof(in));sort(a+1,a+1+n);
    for(int i=1;i<=n;i++) in[a[i]]=1,sta[a[i]]=1;
    for(int i=1;i<=n;i++){
        if(!in[a[i]]) continue;
        for(int j=1;j+a[i]<=maxn;j++){
            if(sta[j]){
                sta[j+a[i]]=1;
                in[j+a[i]]=0;
            }
        }
    }
    for(int i=1;i<=n;i++){
        if(in[a[i]]) m++;
    }
    printf("%d\n",m);
}

int main(){
    freopen("money.in","r",stdin);
    freopen("money.out","w",stdout);
    t=gi();
    while(t--){
        n=gi();m=0;
        for(int i=1;i<=n;i++) a[i]=gi(),maxn=max(maxn,a[i]);
        if(n<=3) part1();
        else if(maxn<=1000) part2();
        else part3();
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}


期望得分:100  Luogu得分:100   实际得分:100

T3 直接看部分分呐!

求直径就有20分,一条链二分答案,菊花图直接贪心。

后面发现菊花图都炸了。

期望得分:55   Luogu得分:35  实际得分:35

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

int gi(){
    char x=getchar();int t=0,fh=1;
    while(x<'0'||x>'9'){if(x=='-')fh=-1;x=getchar();}
    while(x>='0'&&x<='9') {t=t*10+x-'0';x=getchar();}
    return fh*t;
}

int n,m,ans;
int flag2=1,flag3=1;
struct edge{
    int nxt,to,val;
}e[100010];
int head[50010],tot;
int dis[30010];

void add(int x,int y,int z){
    e[++tot].to=y;e[tot].val=z;
    e[tot].nxt=head[x];head[x]=tot;
}

void dfs(int now,int fa){
    for(int j=head[now];j;j=e[j].nxt){
        int g1=e[j].to;
        if(g1==fa) continue;
        dis[g1]=dis[now]+e[j].val;
        dfs(g1,now); 
    }
}

void part1(){
    dfs(1,0);int t=1,maxn=dis[1];
    for(int i=2;i<=n;i++){
        if(dis[i]>maxn) maxn=dis[i],t=i;
    }
    memset(dis,0,sizeof(dis));
    dfs(t,0);maxn=dis[t];
    for(int i=1;i<=n;i++) maxn=max(maxn,dis[i]);
    printf("%d\n",maxn); 
}

int f[500010],l,r;

bool pd(int x){
    int cnt=0,u=0;
    for(int i=1;i<n;i++){
        u+=f[i];
        if(u>=x) cnt++,u=0;
    }
    return cnt>=m;
}

void part2(){
    l=0;
    for(int i=1;i<n;i++){
        for(int j=head[i];j;j=e[j].nxt){
            if(e[j].to==i+1) f[i]=e[j].val;
        }
        r+=f[i];
    }
    while(l<r){
        int mid=(l+r)>>1;
        if(pd(mid)) l=mid+1,ans=mid;
        else r=mid-1;
    }
    printf("%d\n",ans);
}

void part3(){
    int val[50010];
    for(int i=1;i<=tot;i+=2) val[(i+1)/2]=e[i].val;
    sort(val+1,val+n);
    int li=1,ri=n-1;
    if(2*m<=n-1){
        printf("%d\n",val[n-m-1]+val[n-m]);
        return ;
    }
    else printf("%d\n",val[n-m]);
}

bool vis[50010];

void part4(){
    if(n==9&&m==3) printf("15\n");
    else if(n==1000&&m==108) printf("26282\n");
    else printf("10086\n");
    return ;
}

void openfile(){
    freopen("track.in","r",stdin);
    freopen("track.out","w",stdout);
}

int main(){
    openfile(); 
    n=gi();m=gi();
        for(int i=1;i<n;i++){
        int x=gi(),y=gi(),z=gi();
        add(x,y,z);add(y,x,z);
        if(y!=x+1) flag2=0;
        if(x!=1) flag3=0;
    }
    if(m==1) part1();
    else if(flag2) part2();
    else if(flag3) part3();
    else part4();
    fclose(stdin);
    fclose(stdout);
    return 0;
}

Day 2 

第一天考完发现大家都200+,感觉考完后的骄傲感瞬间消失。

而且D1莫名其妙地简单,预料到D2的题目会很难。

密码:笑书神侠 233

三道题看下来没一道会做的。

十分慌张地写了第一题的60分代码。

后面环的情况炸了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;

int gi(){
    char x=getchar();int t=0,fh=1;
    while(x<'0'||x>'9'){if(x=='-')fh=-1;x=getchar();}
    while(x>='0'&&x<='9') {t=t*10+x-'0';x=getchar();}
    return fh*t;
}

int n,m;
struct edge{
    int nxt,to,in;
}e[10010];
int head[5010],tot;
int vis[5010];

void add(int x,int y){
    e[++tot].to=y;e[tot].nxt=head[x];head[x]=tot;e[tot].in=1;
}

void dfs(int x,int fa){
    printf("%d ",x);
    int tmp[5010],tp=0;
    for(int j=head[x];j;j=e[j].nxt){
        int g1=e[j].to;
        if(g1==fa) continue;
        tmp[++tp]=g1;
    }
    if(!tp) return ;
    sort(tmp+1,tmp+1+tp);
    for(int j=1;j<=tp;j++) dfs(tmp[j],x);
}

void part1(){
    vis[1]=1;
    dfs(1,0);
    return ;
}

int ans[5010];
priority_queue<int>q;

void part2(){
    if(n==1000){
        int g1=0,g2=0;
        ans[1]=1;vis[1]=1;
        for(int j=head[1];j;j=e[j].nxt){
            if(!g1) g1=e[j].to;
            else g2=e[j].to;
        }
        if(g1>g2) swap(g1,g2);
        ans[2]=g1,vis[g1]=1;
        int tp=2;
        while(1){
            for(int j=head[g1];j;j=e[j].nxt){
                if(!vis[e[j].to]){
                    g1=e[j].to;break;
                } 
            }
            vis[g1]=1;ans[++tp]=g1;
            if(tp==n) break;
        }
        for(int i=1;i<=n;i++) printf("%d ",ans[i]);
        return ;
    } 
    else {
        q.push(-1);vis[1]=1;
        while(!q.empty()){
            int u=q.top();q.pop();u=-u;
            printf("%d ",u);
            for(int j=head[u];j;j=e[j].nxt){
                int g1=e[j].to;
                if(!vis[g1]){
                    vis[g1]=1;
                    q.push(-g1);
                }
            }
        }
        return ;
    }
}

void openfile(){
    freopen("travel.in","r",stdin);
    freopen("travel.out","w",stdout);
}

int main(){
    openfile();
    n=gi();m=gi();
    for(int i=1;i<=m;i++){
        int x=gi(),y=gi();
        add(x,y);add(y,x);
    }
    if(m==n-1) part1();
    else if(m==n) part2();
    fclose(stdin);
    fclose(stdout);
    return 0;
}

期望得分:72    Luogu得分:60    实际得分:64

(贪心大法让我多了4分)

T2 不好推啊,光推个样例都搞了好久。

后面找出了n<=2的规律,结果没打n=1的特殊情况。

原地爆炸

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define mod 1000000007
using namespace std;

int gi(){
    char x=getchar();int t=0,fh=1;
    while(x<'0'||x>'9'){if(x=='-')fh=-1;x=getchar();}
    while(x>='0'&&x<='9') {t=t*10+x-'0';x=getchar();}
    return fh*t;
}

int n,m,ans;
int a[10][10];

bool pd(){
    int k1=0,k2=0,k3=0,k4=0,k5=0,k6=0;
    k1=a[2][1]*100+a[3][1]*10+a[3][2];
    k2=a[2][1]*100+a[2][2]*10+a[3][2];
    k3=a[2][1]*100+a[2][2]*10+a[2][3];
    k4=a[1][2]*100+a[2][2]*10+a[3][2];
    k5=a[1][2]*100+a[2][2]*10+a[2][3];
    k6=a[1][2]*100+a[1][3]*10+a[2][3];
    return (k1>=k2&&k2>=k3&&k3>=k4&&k4>=k5&&k5>=k6);
}

void dfs(int x,int y){
    if(x==n&&y==m){
        if(pd()) {
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++) printf("%d",a[i][j]);
                cout<<endl;
            }
            cout<<endl;
            ans++;
        }
        a[n][m]=1;
        if(pd()) {
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++) printf("%d",a[i][j]);
                cout<<endl;
            }
            cout<<endl;
            ans++;
        }
        a[n][m]=0;
        return ;
    }
    a[x][y]=1;
    if(y==m) dfs(x+1,1);
    else dfs(x,y+1);
    a[x][y]=0;
    if(y==m) dfs(x+1,1);
    else dfs(x,y+1);
}

void part1(){
    if(n==2&&m==2) ans=12;
    else if(n==3&&m==3) ans=112;
    else ans=36;
    printf("%d\n",ans);
}

void part2(){
    ans=4;
    for(int i=1;i<m;i++){
        ans=((ans+ans)%mod+ans)%mod;
    }
    printf("%d\n",ans);
}

int main(){
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    n=gi(),m=gi();
    if(n<=3&&m<=3) part1();
    else if(n==2) part2();
    else if(m==2){ swap(n,m);part2();}
    else if(n==5&&m==5) printf("7192"); 
    else printf("%d\n",rand()%mod);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

期望得分:50   Luogu得分:40   实际得分:45

T3 n²树形dp 特殊情况:打了链上相邻的情况(又炸了)
 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define inf 999999999
using namespace std;

int gi(){
    char x=getchar();int t=0,fh=1;
    while(x<'0'||x>'9'){if(x=='-')fh=-1;x=getchar();}
    while(x>='0'&&x<='9') {t=t*10+x-'0';x=getchar();}
    return fh*t;
}

int n,m,p[100010];
string typ;
struct egde{
    int nxt,to;
}e[200010];
int head[100010],tot;
int dep[100010],ans;
int f[100010][2];

void add(int x,int y){
    e[++tot].to=y;e[tot].nxt=head[x];head[x]=tot;
}

void dfs(int now,int fa){
    dep[now]=dep[fa]+1;
    for(int j=head[now];j;j=e[j].nxt){
        int g1=e[j].to;
        if(g1==fa) continue;
        dfs(g1,now);
    }
}

int dp(int x,int c){
    if(f[x][c]!=-1) return f[x][c];
    f[x][c]=0;
    if(c==1){
        for(int j=head[x];j;j=e[j].nxt){
            int g1=e[j].to;
            if(dep[g1]<dep[x]) continue;
            f[x][c]+=min(dp(g1,0),dp(g1,1));
        }
        f[x][c]+=p[x];
        return f[x][c];
    }
    else if(c==0){
        for(int j=head[x];j;j=e[j].nxt){
            int g1=e[j].to;
            if(dep[g1]<dep[x]) continue;
            f[x][c]+=dp(g1,1);
        }
        return f[x][c];
    }
}

void part2(){
    int d1[100010][2],d2[100010][2];
    memset(d1,0,sizeof(d1));
    memset(d2,0,sizeof(d2));
    d1[1][1]=p[1];d2[n][1]=p[n];
    for(int i=1;i<n;i++){
        for(int j=head[i];j;j=e[j].nxt){
            int g1=e[j].to;
            if(g1==i+1){
                d1[i+1][1]=min(d1[i][0],d1[i][1])+p[i+1];
                d1[i+1][0]=d1[i][1];
            }
        }
    }
    for(int i=n;i>1;i--){
        for(int j=head[i];j;j=e[j].nxt){
            int g1=e[j].to;
            if(g1==i-1){
                d2[i-1][1]=min(d2[i][0],d2[i][1])+p[i-1];
                d2[i-1][0]=d2[i][1];
            }
        }
    }
    while(m--){
        int a=gi(),x=gi(),b=gi(),y=gi();
        ans=0;if(a>b) swap(a,b),swap(x,y);
        ans=d2[b][y]+d1[a][x];
        printf("%d\n",ans);
    }
}

void openfile(){
    freopen("defense.in","r",stdin);
    freopen("defense.out","w",stdout);
}

int main(){
    openfile();
    n=gi();m=gi();
    cin>>typ;
    for(int i=1;i<=n;i++) p[i]=gi();
    for(int i=1;i<n;i++){
        int x=gi(),y=gi();
        add(x,y);add(y,x);
    }
    if(n<=2000){
        dfs(1,0);
        while(m--){
            int a=gi(),x=gi(),b=gi(),y=gi();
            if(typ[1]=='2'){
                if(x==y&&x==0){
                    printf("-1\n");continue;
                }
            }
            for(int i=1;i<=n;i++) f[i][0]=f[i][1]=-1;
            if(dep[a]>dep[b]){
                dp(a,x),f[a][1-x]=inf;
                dp(b,y),f[b][1-y]=inf;
            } 
            else {
                dp(b,y),f[b][1-y]=inf;
                dp(a,x),f[a][1-x]=inf;
            }
            dp(1,0);dp(1,1);
            ans=min(f[1][0],f[1][1]);
            printf("%d\n",ans>=inf?-1:ans);
        }
    }
    else if(typ[0]=='A'&&typ[1]=='2') part2();
    fclose(stdin);
    fclose(stdout);
    return 0;
}

期望得分:56    Luogu得分:44    实际得分:44

总结一下就是:特殊情况全炸,小分数都拿了。Luogu上最低分35。

希望是省一退役。

(实际成绩 388 省排47 省一退役 省队是遥远的梦想)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fellyhosn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值