NOIP2017提高组模拟赛4 (总结)
来源:互联网 发布:中企动力java面试 编辑:程序博客网 时间:2024/05/22 09:47
NOIP2017提高组模拟赛4 (总结)
第一题 约数
这道题就是很简单的bfs,可以观察到n变化到m是近似成倍增长的。其实从最小到最大的变化也就只有30次而已。
#include<cstdio>#include<algorithm>#include<cmath>typedef long long ll;using namespace std;const int maxl=100;const int oo=1e9;const int N=100000;int T,n,m;int op[N+10],ct,ch,f[N+10];bool uss[N+10];int main(){ freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=1;i<=N;i++) f[i]=oo,uss[i]=0; f[n]=0; ct=ch=1; op[ct]=n; while(ch<=ct) { if(op[ch]<m && f[op[ch]]<maxl) { int i=floor(sqrt(op[ch])); i=(m<op[ch]+i)?m-op[ch]:i; for(;i>=2;i--) { if(op[ch]%i==0) { if(op[ch]+i<=m && f[op[ch]]+1<f[op[ch]+i]) { if(!uss[op[ch]+i]) op[++ct]=op[ch]+i,uss[op[ch]+i]=1; f[op[ch]+i]=f[op[ch]]+1; //printf("%d %d -> %d %d\n",op[ch],f[op[ch]],op[ch]+i,f[op[ch]+i]); } if(i*i!=op[ct]) { int yu=op[ch]+op[ch]/i; if(yu<=m && f[op[ch]]+1<f[yu]) { if(!uss[yu]) op[++ct]=yu,uss[yu]=1; f[yu]=f[op[ch]]+1; //printf("%d %d -> %d %d\n",op[ch],f[op[ch]],yu,f[yu]); } } } } } uss[op[ch]]=0; ch++; } printf("%d\n",(f[m]!=oo)?f[m]:-1); } return 0;}
第二题 警察与小偷
这是一道好题,数据很大,但边是双向的,只是删一条边或一个点,而且保证了点两两之间是连通的。(这些很重要)
那么,可以从dfs序入手,dfs序是一棵树,其中会有返祖边。(如图)
那我们只需要判断删掉的点或边是否在u到v的路径上,不在的话,删了也没用。(用三次lca处理)。
如果删的是边,判断边的左右端点是否为一个块,(dfn[a]>dfn[b] 且 low[a]≤dfn[b])是的话,删了还是u,v保持连通的,否则u,v不连通,(必经路被删)
如果删的是点c。lca—u,v的公共祖先
若c在u->lca的路径上,则更新uminlow(能到达的最早的点)。
若c在v->lca的路径上,则更新vminlow(能到达的最早的点)。
判断uminlow和vminlow都小于c就保证了u,v之间连通。
否则不连通。
#include<cstdio>#include<algorithm>#include<cstring>#define imax(a,b) ((a>b)?(a):(b))#define imin(a,b) ((a<b)?(a):(b))typedef long long ll;using namespace std;const int mm=500100;const int nn=100100;int N,E,Q,dt,TN;bool vis[nn];int ti[nn],low[nn];int ne[mm<<1],to[mm<<1],h[nn],tt;int f[nn][20];void addedge(int a,int b){ to[++tt]=b; ne[tt]=h[a]; h[a]=tt; to[++tt]=a; ne[tt]=h[b]; h[b]=tt;}void dfs(int x,int fa){ f[x][0]=fa; ti[x]=low[x]=++dt; vis[x]=1; for(int p=h[x];p;p=ne[p]) { int u=to[p]; if(u==fa) continue; if(!vis[u]) dfs(u,x); low[x]=imin(low[x],low[u]); }}int lca(int a,int b){ if(a==b) return a; if(ti[a]<ti[b]) swap(a,b); for(int i=TN;i>=0;i--) if(ti[f[a][i]]>ti[b]) a=f[a][i]; return (f[a][0]);}int mingo(int a,int b){ for(int i=TN;i>=0;i--) if(ti[f[a][i]]>ti[b]) a=f[a][i]; return a;}bool judge(int u,int v,int a){ int w=lca(u,v); int x=lca(u,a); int y=lca(v,a); if(x!=a) swap(x,y); return (x==a && y==w);}int main(){ freopen("b.in","r",stdin); freopen("b.out","w",stdout); scanf("%d%d",&N,&E); tt=1; for(int i=1;i<=E;i++) { int A,B; scanf("%d %d",&A,&B); addedge(A,B); } ti[0]=low[0]=0; dt=0; dfs(1,0); f[1][0]=1; TN=0; for(int i=1;(1<<(i-1))<N;i++) { TN++; for(int j=1;j<=N;j++) f[j][i]=f[f[j][i-1]][i-1]; } scanf("%d",&Q); for(int i=1;i<=Q;i++) { int ww,a,b,c,d; scanf("%d",&ww); if(ww==1) { scanf("%d%d%d%d",&a,&b,&c,&d); if(ti[a]<ti[b]) swap(a,b); if(ti[c]<ti[d]) swap(c,d); if(judge(a,b,c) && judge(a,b,d)) { if(low[c]<=ti[d]) printf("yes\n"); else printf("no\n"); } else printf("yes\n"); } else if(ww==2) { scanf("%d%d%d",&a,&b,&c); if(ti[a]<ti[b]) swap(a,b); if(judge(a,b,c)) { if(lca(a,b)==c) { int xx=mingo(a,c),yy=mingo(b,c); if(low[xx]<ti[c] && low[yy]<ti[c]) printf("yes\n"); else printf("no\n"); } else { int dp=0; if(lca(a,c)==c) dp=a; else dp=b; int xx=mingo(dp,c); if(low[xx]<ti[c]) printf("yes\n"); else printf("no\n"); } } else printf("yes\n"); } } return 0;}
第三题 圆桌会议
一道贪心的题目。
假设不是一个环,而是一条链,那该怎么做?
很显然,低-高-低这类是不可能的,因为低-低-高肯定比它更优。
是环的话,最低-最高这肯定是不行的,因为需要最大的最小。
可以考虑数列拆成两部分(排序后按A5-A3-A1-A2-A4-A6这样排)。
这样是最优的,详细证明如下:
A5-A3-A1-A2-A4-A6,假设A4-A6最大,可以改得更优,A5移过来,变成A3-A1-A2-A4-A5-A6,那么A3-A6比A4-A6跟大,答案肯定不会优。
其他情况也差不多。
Ai和Ai+1之间肯定改不了(-_-|| 显然的)。
字典序怎么办?先求出minans,然后放A1,在右侧放A2,判断A4和当前头的距离是否合法(小于等于minans),不合法的话A3只能放在头的左侧作为新的头(不合法的话,再将A3放在右侧的话,A4就没法放了 放左或放右都会使最大距离大于minans),合法的话就将A3放在右侧,以此类推。
#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define imax(a,b) ((a>b)?(a):(b))typedef long long ll;using namespace std;bool cmp(int a,int b) { return (a<b); }int ng,n,d[60],ans,p[60];int ya[60],yb[60],l1,l2;int main(){ freopen("c.in","r",stdin); freopen("c.out","w",stdout); scanf("%d",&ng); while(ng--) { scanf("%d",&n); ans=0; for(int i=1;i<=n;i++) scanf("%d",&d[i]); sort(d+1,d+1+n); int w=(n+1)>>1,q=1,cc=w; p[w]=d[1]; for(int i=2;i<=n;i++) { if((i&1)==0) w+=q; else w-=q; p[w]=d[i]; q++; } ans=abs(p[1]-p[n]); for(int i=2;i<=n;i++) ans=imax(ans,abs(p[i]-p[i-1])); l1=1; l2=1; ya[1]=d[1]; yb[1]=d[1]; for(int i=2;i<=n;i++) { if(abs(d[i+1]-yb[l2])>ans) yb[++l2]=d[i]; else ya[++l1]=d[i]; } for(int i=1;i<=l1;i++) printf("%d ",ya[i]); for(int i=l2;i>=2;i--) printf("%d ",yb[i]); printf("\n"); } return 0;}
考的不怎么好,没状态,最后一题想出来但字典序问题没搞好。争取在每一次考试中都能不断进步吧!
超越自己,让自己变得更好 ————加油,努力
- NOIP2017提高组模拟赛4 (总结)
- NOIP2017提高组模拟赛5 (总结)
- NOIP2017提高组模拟赛 7(总结)
- NOIP2017提高组模拟赛 8(总结)
- NOIP2017提高组模拟赛 9 (总结)
- NOIP2017提高组模拟赛 10 (总结)
- NOIP2017提高组 模拟赛13(总结)
- NOIP2017提高组 模拟赛15(总结)
- NOIP2017提高组 模拟赛16(总结)
- NOIP2017提高组 模拟赛17(总结)
- NOIP2017提高组 模拟赛18(总结)
- NOIP2017提高组 模拟赛19(总结)
- NOIP2017提高组 模拟赛20(总结)
- NOIP2017提高组 模拟赛21(总结)
- NOIP2017提高组 模拟赛23(总结)
- NOIP2017提高组 模拟赛24(总结)
- NOIP2017提高组 模拟赛 26(总结)
- NOIP2017提高组 模拟赛 27(总结)
- Java 注解
- 将H264码流打包成RTP包
- Appium Hybrid混合应用测试——Native切换WebView(转)
- Android串口通讯
- 如何用WPS表格制作甘特图?WPS表格制作甘特图详解!
- NOIP2017提高组模拟赛4 (总结)
- SpringMVC-Spring-MyBatis-Freemarker整合+源码下载
- Linux mkdir&rm命令
- STM32F1x系列——Flash 模拟 EEPROM
- ionc2应用打包签名流程
- python-list
- Effective c++ 学习笔记(四)
- spring mvc redirect 传递参数 和接收
- 微信小程序导航:官方文档+精品教程+demo集合(6月12日更新)