隐藏页面特效

NOI Day1线上同步赛梦游记

1|0Preface


第一次体验NOI,虽然不是正式选手,但是打打同步赛还是挺涨姿势的,也算是体验了一把。

Day1很爆炸,一方面是NOI题目的难度高于自身的水平,另一方面也出现了比较大的失误,T1一个数组没有清空导致树的部分分全部爆0了;T3可能是蜜汁Hash写挂(or 题意理解错误?)导致暴力(不过话说好多网络赛的人T3都爆零了)

不禁想到如果是自身参加NOI虽然不太现实,出现这样的SB错误会不会后悔呢?

后面两题不会,静候未来填坑。


2|0归程


整套题目看起来唯一可做的题目(对于我来说),所以读完题目就马上看了下部分分

woc,CCF这么良心的吗?所以就来了一波大力分类讨论:

  • 前30pts(16):海拔仅有一种且为1,这不是良心送分么?我从终点开始往回刷一遍DJ(别问我为什么不用SPFA),每一次判断洪水高度是否>1即可,若是直接输出最短路径(反正一条路都没有了,只能靠脚了),否则输出0(直接飙车到达即可)
  • 后面的10pts(1516):注意到数据范围很小,我们还是先预处理。对于每一次询问,我们从起点开始BFS,期间只能经过高度大于洪水高度的边,然后再所以能够到达的点中找出离终点最近的点击即可。
  • 中间的25pts(711):保证数据为链or树,由于树的特殊性,我们直接考虑树怎么做。首先最短路是要跑的(直接用DJ也行,不过自己再写一个BFS什么的会更快),然后我们直接以终点为根,预处理出LCA数组(用来跳father)以及倍增数组(记录每一段树链上权值最小的边)。考虑洪水淹没的过程,只要一条边断了,这条路就不得不停止。所以我们树上倍增找到第一条被淹没的边,然后在输出这个点到根的路径长度即可(用前面的两个数组做类似于倍增LCA的过程)。
  • 中间的15pts(1314):这个我们注意到离线这个重要性质。我们把所以操作读进来,按洪水高度从大到小排个序。这时候我们发现对于操作的进行其实就是个不断地给原图加边的一个过程,所以我们用并查集维护,顺便维护每一个联通块内的点距离终点最近的距离即可。

然后满分算法蒟蒻就不会了,其实按照上面的离线方法是可以跑在线的情况的,只不过需要可持久化并查集。然后由于我很菜,一直都没调出来,所以还是等着以后再填吧。

具体同步赛的时候由于树的情况倍增数组没有清空,所以少得了15pts(还好我把链和暴力一起做了),并且最后离线想到了懒得写了(在刚T2,T3)

这里上分类讨论CODE(能过前16组数据,所以在Luogu上这一题显示过了,好像还很快

#include<cstdio> #include<cctype> #include<cstring> #include<queue> #include<algorithm> using namespace std; const int N=2e5+5,M=4e5+5,MINER_N=1505,P=21; struct edge { int to,next,v,h; }e[M<<1]; struct data { int num,s; bool operator <(const data a) const { return a.s<s; } }; struct double_edge { int l,r,s; }a[M]; struct ques { int x,h,id; }b[N>>1]; priority_queue<data> small; int n,m,q,k,s,ans,x,y,l,h,cnt,head[N],dis[N],t,que[MINER_N],f[N][P],father[N][P],sum[N],fa[N],Ans[N>>1]; bool flag,vis[N],get[MINER_N]; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); } inline void write(int x) { if (x>9) write(x/10); putchar(x%10+'0'); } inline void double_add(int x,int y,int v,int h) { e[++cnt].to=y; e[cnt].next=head[x]; e[cnt].v=v; e[cnt].h=h; head[x]=cnt; e[++cnt].to=x; e[cnt].next=head[y]; e[cnt].v=v; e[cnt].h=h; head[y]=cnt; } inline int min(int a,int b) { return a<b?a:b; } inline void clear(void) { memset(head,-1,sizeof(head)); cnt=ans=0; flag=1; memset(f,0,sizeof(f)); memset(sum,0,sizeof(sum)); } inline void Dijkstra(int s) { memset(dis,63,sizeof(dis)); memset(vis,0,sizeof(vis)); small.push((data){s,0}); dis[s]=0; while (!small.empty()) { int now=small.top().num; small.pop(); if (vis[now]) continue; vis[now]=1; for (register int i=head[now];~i;i=e[i].next) if (dis[e[i].to]>dis[now]+e[i].v) { dis[e[i].to]=dis[now]+e[i].v; small.push((data){e[i].to,dis[e[i].to]}); } } } inline void reset(int now) { for (register int i=0;i<P-1;++i) if (father[now][i]) father[now][i+1]=father[father[now][i]][i],f[now][i+1]=min(f[now][i],f[father[now][i]][i]); } inline void DFS(int now,int fa) { register int i; father[now][0]=fa; reset(now); for (i=head[now];~i;i=e[i].next) if (e[i].to!=fa) f[e[i].to][0]=e[i].h,sum[e[i].to]=sum[now]+e[i].v,DFS(e[i].to,now); } inline void solve1(int x,int h) { write(ans=(h>=1?dis[x]:0)); putchar('\n'); } inline void solve2(int x,int h) { for (register int i=P-1;i>=0;--i) if (father[x][i]&&f[x][i]>h) x=father[x][i]; write(ans=sum[x]); putchar('\n'); } inline void solve3(int x,int h) { register int i,H=0,T=1; memset(get,0,sizeof(get)); que[1]=x; get[x]=1; int res=dis[x]; while (H<T) { int now=que[++H]; for (i=head[now];~i;i=e[i].next) if (e[i].h>h&&!get[e[i].to]) res=min(res,dis[e[i].to]),get[e[i].to]=1,que[++T]=e[i].to; } write(ans=res); putchar('\n'); } inline bool cmp1(double_edge a,double_edge b) { return a.s>b.s; } inline bool cmp2(ques a,ques b) { return a.h>b.h; } inline int getfa(int k) { return k^fa[k]?fa[k]=getfa(fa[k]):k; } inline void unionn(int x,int y) { int fx=getfa(x),fy=getfa(y); if (fx!=fy) { if (dis[fx]<dis[fy]) fa[fy]=fx; else fa[fx]=fy; } } inline void solve4(void) { register int i,p=1; for (i=1;i<=q;++i) read(b[i].x),read(b[i].h),b[i].id=i; sort(a+1,a+m+1,cmp1); sort(b+1,b+q+1,cmp2); for (i=1;i<=n;++i) fa[i]=i; for (i=1;i<=q;++i) { while (p<m&&a[p].s>b[i].h) unionn(a[p].l,a[p].r),++p; Ans[b[i].id]=dis[getfa(b[i].x)]; } for (i=1;i<=q;++i) write(Ans[i]),putchar('\n'); } int main() { //freopen("return.in","r",stdin); freopen("return.out","w",stdout); register int i; read(t); while (t--) { read(n); read(m); clear(); for (i=1;i<=m;++i) { read(x); read(y); read(l); read(h); a[i]=(double_edge){x,y,h}; double_add(x,y,l,h); if (h^1) flag=0; } if (m!=n-1) Dijkstra(1); else DFS(1,0); read(q); read(k); read(s); if (!k&&q==100000&&!flag&&m!=n-1) { solve4(); continue; } while (q--) { read(x); read(y); x=(1LL*x+k*ans-1)%n+1; y=(1LL*y+k*ans)%(s+1); if (flag) { solve1(x,y); continue; } if (m==n-1) solve2(x,y); else solve3(x,y); } } return 0; }

3|0冒泡排序


那个板子其实刚开始是错的而且同步赛好像并没有更正

蒟蒻表示这种数学向的题目太恐怖,所以一直企图切出前11个点的状压DP

然而什么也没搞出来,最后交了个全排列证明我曾经来过水了8分


4|0你的名字


字符串什么也不会好吧Hash的奇技淫巧我还是挺熟练的的菜鸡表示看到题目直接弃疗。

直奔12pts的Hash暴力而去,最后爆0了,我应该是看错题意了。

反正一堆dalao说着线段树套SAM过,我还是回去老老实实学ACWA自动机吧


5|0Postscript


反正我太菜了也没什么关系只要不是真的NOI爆炸我还是可以接受的

争取明年同步赛不要翻低级错误不敢说出去NOI的我


__EOF__

本文作者hl666
本文链接https://www.cnblogs.com/cjjsb/p/9457858.html
关于博主:复活的ACM新生,目前爱好仅剩Gal/HBR/雀魂/单机/OSU
版权声明:转载请注明出处
声援博主:欢迎加QQ:2649020702来DD我
posted @   空気力学の詩  阅读(267)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示