NOIp2017 题解
Day1
T1 小凯的疑惑
题目传送门
考场上打表搞了一个很奇怪的结论,化简后就是a∗b−a−ba*b-a-ba∗b−a−b。具体证明现在还是不大会。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
LL a,b;
int main(){scanf("%lld%lld",&a,&b);if (a>b) swap(a,b);if (a==1){printf("0\n");return 0;}if (a==2){printf("%lld\n",b-2);fclose(stdin);fclose(stdout);return 0;}LL ans=(4+(a-3)*2+4)*(a-2)/2+1;ans+=(b-a-1)*(a-1);printf("%lld\n",ans);return 0;
}
T2 时间复杂度
题目传送门
一般用一个栈模拟,细节比较多。没什么好说的。
考场上写的代码只会统计第一个循环。。。然而还是有80。
当时太紧张就写得很丑。
代码:
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 100
using namespace std;
struct Orz{char c;bool f;
}stack[MAXN+5];
int top,t,l,cmp,a[MAXN+5],ma;
int f;
char s[MAXN+5],sc[MAXN+5],sx[MAXN+5],sy[MAXN+5];
int main(){scanf("%d",&t);while (t--){memset(a,0,sizeof(a));f=0; top=0; cmp=0; ma=0;scanf("%d%s",&l,s);if (s[2]=='n') f=1;for (int i=0;s[i];i++)if (s[i]>='0'&&s[i]<='9')cmp=cmp*10+s[i]-48;int num=0;bool flag=false,fa=false,fl=false; if (l&1) flag=true;for (int i=1;i<=l;i++){int ff=0; char ss[2];scanf("%s",ss);ff=ss[0];if (ff=='F'){int c,x=0,y=0;scanf("%s%s%s",sc,sx,sy);c=sc[0];for (int j=0;sx[j];j++)if (sx[j]>='0'&&sx[j]<='9')x=x*10+sx[j]-48;for (int j=0;sy[j];j++)if (sy[j]>='0'&&sy[j]<='9')y=y*10+sy[j]-48;if (sx[0]=='n') x='n';if (sy[0]=='n') y='n';if (flag) continue;if (a[c-'a']){ flag=true; continue; }if (x=='n'&&y!='n') fl=true;if (x!='n'&&y!='n'&&x>y) fl=true;if (x!='n'&&y=='n') num++;if (x!='n'&&y=='n'&&(!fl)) fa=true,ma=max(ma,num);a[c-'a']++; Orz p; p.c=c;if (x!='n'&&y=='n') p.f=true;else p.f=false;stack[++top]=p;}else{if (!top) { flag=true; continue; }if (stack[top].f) num--;a[stack[top--].c-'a']--;if (!top) fl=false;}}if (top) flag=true;if (flag){printf("ERR\n");continue;}if ((fa&&(f==0))||(ma!=cmp&&(f==1))){printf("No\n");continue;}printf("Yes\n");}return 0;
}
T3 逛公园
题目传送门
最短路+记忆化搜索
考场上用最短路优化一下就有60了。。。
先刷一遍反图最短路求出每个点到nnn的最短路dis[i]dis[i]dis[i]。
记f[i][j]f[i][j]f[i][j]表示到第iii个点,超出最短路的路程≤j\leq j≤j的方案数。搜索的时候对每条边的转移f[i][j]=∑f[v][j−d]f[i][j]=\sum f[v][j-d]f[i][j]=∑f[v][j−d]。其中d=dis[v]−dis[i]+wd=dis[v]-dis[i]+wd=dis[v]−dis[i]+w。判0环的话就记录一下当前状态有没有在访问路径上即可。
代码:
#include<queue>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define F inline
using namespace std;
struct P{ int x,d; };
struct edge{ int nxt,to,d; }ed[N<<2];
int n,m,k,p,K,d[N],h1[N],h2[N],f[N][55];
priority_queue<P> q; bool v[N][55];
F char readc(){static char buf[100000],*l=buf,*r=buf;if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);return l==r?EOF:*l++;
}
F int _read(){int x=0; char ch=readc();while (!isdigit(ch)) ch=readc();while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();return x;
}
#define add(h,x,y,z) ed[++k]=(edge){h[x],y,z},h[x]=k
F bool operator <(P a,P b){ return a.d>b.d; }
F void Dij(){while (!q.empty()) q.pop();for (q.push((P){n,d[n]=0});!q.empty();q.pop()){int x; if (q.top().d>d[x=q.top().x]) continue;for (int i=h2[x],v;i;i=ed[i].nxt)if (d[v=ed[i].to]>d[x]+ed[i].d)d[v]=d[x]+ed[i].d,q.push((P){v,d[v]});}
}
int dfs(int x,int k){if (v[x][k]) return -1; if (f[x][k]) return f[x][k];v[x][k]=true,f[x][k]+=(x==n);for (int i=h1[x],v,w;i;i=ed[i].nxt)if ((w=d[v=ed[i].to]-d[x]+ed[i].d)<=k)if (dfs(v,k-w)==-1) return -1;else (f[x][k]+=f[v][k-w])%=p;return v[x][k]=false,f[x][k];
}
int main(){for (int t=_read();t;t--){n=_read(),m=_read(),K=_read(),p=_read(),k=0;for (int i=1;i<=n;i++) h1[i]=h2[i]=0,d[i]=1e9;for (int i=1;i<=n;i++)for (int j=0;j<=K;j++) f[i][j]=v[i][j]=0;for (int i=1,x,y,z;i<=m;i++){x=_read(),y=_read(),z=_read();add(h1,x,y,z),add(h2,y,x,z);}Dij(),printf("%d\n",dfs(1,K));}return 0;
}
Day2
T1 奶酪
题目传送门
并查集/BFS都可以。本来会爆long long的但是出题人没有卡。判断的时候移个项就好了
代码:
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 1000
#define sqr(x) ((x)*(x))
using namespace std;
typedef long long LL;
struct edge{int next,to;
}ed[MAXN*MAXN*6+5];
struct node{LL x,y,z;
}a[MAXN*2+5];
int t,n,k;
LL m,r;
int h[MAXN*2+5],que[MAXN*2+5];
bool f[MAXN*2+5];
void addedge(int x,int y){ed[++k].next=h[x]; ed[k].to=y; h[x]=k;
}
LL calc(node a,node b){return sqr(a.x-b.x)+sqr(a.y-b.y)+sqr(a.z-b.z);
}
bool bfs(int s,int t){memset(f,false,sizeof(f));int r=0,w=1; que[1]=s; f[s]=true;while (r<w){int x=que[++r];for (int i=h[x];i;i=ed[i].next)if (!f[ed[i].to]){que[++w]=ed[i].to;f[ed[i].to]=true;}}return f[t];
}
int main(){scanf("%d",&t);while (t--){memset(h,0,sizeof(h)); k=0;scanf("%d%lld%lld",&n,&m,&r);for (int i=1;i<=n;i++){scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].z);if (a[i].z<=r) addedge(MAXN+2,i);if (a[i].z+r>=m) addedge(i,MAXN+1); }for (int i=1;i<n;i++)for (int j=i+1;j<=n;j++)if (calc(a[i],a[j])<=sqr(r*2))addedge(i,j),addedge(j,i);if (bfs(MAXN+2,MAXN+1)) printf("Yes\n");else printf("No\n");}return 0;
}
T2 宝藏
题目传送门
状压DP
为什么我会觉得prim是对的!为什么我70分的暴力都不打!果然我好菜
我是不会告诉你我不知道怎么枚子集的
n=12就是状压的范围。据说标算O(4n)O(4^n)O(4n)我不会啊,优化过的O(n3n)O(n3^n)O(n3n)我也不会啊,我只会O(n23n)O(n^23^n)O(n23n)啊不管了能过就行!
Orz写模拟退火的
f[i][j][s]f[i][j][s]f[i][j][s]表示以iii为根的子树中,iii的深度的为jjj,子树中的节点集合为sss的最小代价。那么有f[i][j][s]=min{f[k][j+1][ss]+f[i][j][s−ss]+a[i][k]}f[i][j][s]=min\{f[k][j+1][ss]+f[i][j][s-ss]+a[i][k]\}f[i][j][s]=min{f[k][j+1][ss]+f[i][j][s−ss]+a[i][k]},其中ssssss是sss的子集,kkk为ssssss内的一个点。时间复杂度为O(n33n)O(n^33^n)O(n33n)。
把转移方程中与sss无关的提取出来,预处理g[i][j][s]=min{f[k][j+1][s]+a[i][k]}g[i][j][s]=min\{f[k][j+1][s]+a[i][k]\}g[i][j][s]=min{f[k][j+1][s]+a[i][k]},这样就是O(n23n)O(n^23^n)O(n23n)的了。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 15
#define M (1<<12)+1
using namespace std;
int n,m,ans=1e9,a[N][N],f[N][N][M],g[N][N][M];
int main(){scanf("%d%d",&n,&m);for (int i=1;i<=n;i++)for (int j=1;j<=n;j++){a[i][j]=1e9;for (int s=1;s<1<<n;s++)if (s!=1<<i-1) f[i][j][s]=g[i][j][s]=1e9;}for (int i=1,x,y,z;i<=m;i++)scanf("%d%d%d",&x,&y,&z),a[x][y]=a[y][x]=min(a[x][y],z);for (int j=n-1;j;j--)for (int i=1;i<=n;i++)for (int s=1;s<1<<n;s++){for (int k=1;k<=n;k++)if (((1<<k-1)&s)&&a[i][k]!=1e9)g[i][j][s]=min(g[i][j][s],f[k][j+1][s]+a[i][k]*j);for (int ss=s&s-1;ss;ss=ss-1&s)f[i][j][s]=min(f[i][j][s],f[i][j][s^ss]+g[i][j][ss]);}for (int i=1;i<=n;i++) ans=min(ans,f[i][1][(1<<n)-1]);return printf("%d\n",ans),0;
}
T3 列队
题目传送门
线段树动态开点
去年不会动态开点啊。。。
建n+1棵树,前n棵维护当前这行(除了最后一列),第n+1棵维护最后一列。每次操作的时候分操作的列是不是最后一列讨论一下就好了。
细节有点多,调了好久最后还是借鉴了一下题解。
代码:
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 300005
#define F inline
using namespace std;
typedef long long LL;
struct tree{ int ls,rs,sz; LL x; }t[N<<6];
int n,m,q,mx,nd,rt[N],p[N]; LL ans,tmp;
F char readc(){static char buf[100000],*l=buf,*r=buf;if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);return l==r?EOF:*l++;
}
F int _read(){int x=0; char ch=readc();while (!isdigit(ch)) ch=readc();while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();return x;
}
F void writec(LL x){ if (x>9) writec(x/10); putchar(x%10+48); }
#define pd(l,r,f) (f==n+1?max(min(r,n)-l+1,0):max(min(r+1,m)-l,0))
F void nsrt(int &x,int l,int r,int p,LL w,int f){if (!x) t[x=++nd].sz=pd(l,r,f); int mid=l+r>>1;t[x].sz++; if (l==r) return void(t[x].x=w);if (p<=mid) nsrt(t[x].ls,l,mid,p,w,f);else nsrt(t[x].rs,mid+1,r,p,w,f);
}
F LL srch(int &x,int l,int r,int w,int f){if (!x) t[x=++nd].sz=pd(l,r,f); int mid=l+r>>1,p; t[x].sz--;if (l==r) return t[x].x?t[x].x:t[x].x=(f<=n?1ll*(f-1)*m+l:1ll*l*m);if (w<=(p=t[x].ls?t[t[x].ls].sz:mid-l+1))return srch(t[x].ls,l,mid,w,f);else return srch(t[x].rs,mid+1,r,w-p,f);
}
F LL calc(int x,int y){LL ans,tmp=srch(rt[n+1],1,mx,x,n+1);ans=y!=m?srch(rt[x],1,mx,y,x):tmp;if (y!=m) nsrt(rt[x],1,mx,++p[x],tmp,x);return nsrt(rt[n+1],1,mx,++p[n+1],ans,n+1),ans;
}
int main(){n=_read(),m=_read(),q=_read(),mx=max(n,m)+q;for (int i=1;i<=n+1;i++) p[i]=(i==n+1?n:m-1);for (int x,y;q;q--) x=_read(),y=_read(),writec(calc(x,y)),puts("");return 0;
}
NOIP2018要苟住啊
UPD 2018.11.11 假的,要退役了
NOIp2017 题解相关推荐
- 【NOIP题解】NOIP2017 TG D2T3 列队
列队,NOIP2017 TG D2T3. 树状数组经典题. 题目链接:洛谷. 题意: Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. ...
- NOIP2017提高组初赛 个人理解+题解
NOIP2017复赛总结+题解 今年初赛好难啊 单选 第一题就懵逼 谁知道Pascal什么时候用不了啊 听说是2019年 选项里没有啊 那就2020年吧,果然错,答案是2022 第二题还是很正常,负数 ...
- noip2017爆炸记——题解总结反省(普及组+提高组)
相关链接: noip2018总结 noip2017是我见过的有史以来最坑爹的一场考试了. 今年北京市考点有一个是我们学校,我还恰好被分到了自己学校(还是自己天天上课的那个教室),于是我同时报了普及提高 ...
- 牛客题库 题解 | #[NOIP2017]图书管理员#
链接:#[NOIP2017]图书管理员# 题目牛客网是互联网求职神器,C++.Java.前端.产品.运营技能学习/备考/求职题库,在线进行百度阿里腾讯网易等互联网名企笔试面试模拟考试练习,和牛人一起讨 ...
- 洛谷 P3959 [NOIP2017]宝藏 题解
通向地底的传送门 题目描述 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 \(n\) 个深埋在地下的宝藏屋, 也给出了这 \(n\) 个宝藏屋之间可供开发的$ m$ 条道路和它们的长度. 小明决 ...
- P3955 [NOIP2017 普及组] 图书管理员C++题解
洛谷来源:P3955 [NOIP2017 普及组] 图书管理员 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/sol ...
- [NOIP2017 普及组]跳房子 【题解】
题目背景 NOIP2017 普及组 T4 题目描述 跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一. 跳房子的游戏规则如下: 在地面上确定一个起点,然后在起点右侧画 n n ...
- 【NOIP2017 提高组正式赛】列队 题解
题目大意 有一个 \(n\times m\) 的方阵,每次有 \((x,y)\) 离开,离开后有两个命令 向左看齐.这时第一列保持不动,所有学生向左填补空缺.这条指令之后,空位在第 \(x\) 行第 ...
- NOIP2017金秋冲刺训练营杯联赛模拟大奖赛第二轮Day2题解
肝了两题... T1一眼题,分解质因数,找出2的个数和5的个数取min输出 #include<iostream> #include<cstring> #include<c ...
- NOIP2017(不算是题解)
老年退役选手来过时口胡一波 小凯的疑惑 考场上的普遍做法就是打表吧,规律还是很好找的 很容易看出答案是a*b-a-b 时间复杂度 比16年的D1T2不知道良心多少... 模拟就行了,但还是需要一定的比 ...
最新文章
- ubuntu sudoers配置错误
- iOS:极光推送控制器跳转
- javascript函数,值得参考!
- jvm lock低性能分析
- 爬虫数据传入mysql_nodejs爬虫数据存入mysql
- Opera Unite如何架设自己的网站
- Debian 7 Wheezy 安装 VirtualBox
- STM32 FreeRTOS系列教程(一)FreeRTOS简介
- 点云数据处理(分类、分割、检测)PointNet
- linux 手动修复分区表,分区表修复
- 微信8.0表情没有特效怎么回事
- 接口限流算法(关于临界点处理)
- js前端生成excel文件(表格)并下载
- 企业级和个人苹果帐号AppleId申请
- 暴雪即将公布《暗黑破坏神3》新职业
- html5indexeddb排序,html5的indexedDB数据库操作实例
- MATLAB2018B下用Faster-RCNN做目标检测的训练和测试步骤
- 学法减分助手PRO小程序源码
- Unity打造科技风智慧城市夜景教程
- Python — “输入直角边求斜边”