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 省一退役 省队是遥远的梦想)