noip模拟11
A 送信卒
考场上唐了,把方向搞反导致挂零。。。
然后就是跑一边 bfs,算出来最短路,并且记录横纵位移,就好了。
好像也可以二分然后去跑 djikstra。
其实有个 hack,会让我的代码在特定情况下不稳定地输出错解:
10 10 1 1 5 5 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 1 1 1 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 1 0 1 0 0 0 1 1 1 1 1 0 1 0 1 1 1 1 1 1 1 0 1 0 1 1 1 1 1 1 1 0 1 0 1 1 1 1 1 1 1 0 1 0 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 16
B 共轭树图
首先的结论,是 图是一棵树。
然后省略证明,然后考虑 dp:
设 表示以 为根的子树,且 只允许与它的第 个祖先在 连边时,子树中的方案数。考虑枚举 在 中的父亲具体是哪一个,有转移:
然后在统计时用前缀和优化即可。
C 摸鱼军训
可算是搞懂了。
首先,我们需要确定一个数在 次冒泡排序后的位置,有以下几种可能:
-
第 次排序后前面仍有比他大的数;
-
没有比他大的数
-
他已经不会再移动(前缀已经有序)
首先,有几个比较重要的引理:
若 后方有 个小于它的数,第 个数大于它,那么本次移动 和下一个大于 的数中间的数都会移动到 前方。
证明:
我们设小于 的数为 ,大于 的数为
假设一次排序前的序列为 ,那么显然, 会与 交换,然后指针依然在 上,会与 交换,直到 为止。而接下来 会从 和 中间移动到 和 中间,以此类推。
若 前方已无大于它的数,且保证接下来的序列一定会变,那连续 次排序,第 次排序后 应该距离 在序列中的原位置有 长度。
证明:
我们已知一次排序后 会处在某个大于它的数的前面,那么根据上面的结论,第 次排序会使 和 中间的所有 移动到 和 中间,
此时,我们假设序列中没有 的数,那排序到 次时确实距离 为 。
那现在有了 的数,原序列中 前面的、 的数来到了 的前方,假设有 个,
我们不关心 后方的数产生的影响,因为在 次后它们到不了 的前面,即对 现在的位置没有影响。
假设原序列中 到 的距离为 ,即有 个大于 的, 个小于 的,
那么既然那 个 的数已然来到 前方,所以 到 的原位置不就是 ,那不就是 吗。
情况 :
若 前面仍有大于它的数,那距离 最近的、大于 的数一定会移动到 后方。证明可看引理 1。
那么,有 个大于 的数,就一定需要 轮去把它们移动到 后方。并且,每移动一轮, 的位置都会 。
因为有一个在它前面的大于它的数到了后面,且只有一个,所以会 。
记原序列中在位置 前方且大于 的数的个数为 ,那么对于所有 的轮, 的位置一定是 。
情况 :
此时, 的前方已经没有比它大的数了,那我们根据引理 2,在第 轮, 到 原位置的距离为 ,只需要维护所有大于 的数的位置,并且找第 大的,那么本次排序后 的位置就是 了。
情况 :
在第 轮,编号为 的数一定会被移动到最终位置。
点击查看代码
#include<bits/stdc++.h> using namespace std; #define int long long int n; const int N=5e5+5; inline int read() { register int s=0; register char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') s=(s<<1)+(s<<3)+(c^48),c=getchar(); return s; } void write(int x) { if(x>9) write(x/10); putchar(x%10+'0'); } int q,a[N]; struct OP{ int k,x,id; inline bool operator<(const OP &ll) const { return x>ll.x; } }op[N]; int ans[N],pos[N]; struct BIT{ int c[N]; inline int lowbit(int x) { return x&-x; } void update(int x) { for(;x<=n;x+=lowbit(x)) c[x]++; } int query(int x) { int res=0; for(;x;x-=lowbit(x)) res+=c[x]; return res; } }st1; int rev[N]; struct SegTree{ struct{ int sum; }tr[N<<2]; #define lid now<<1 #define rid now<<1|1 void update(int now,int l,int r,int x,int y) { if(x<=l&&r<=y) { tr[now].sum++;return ; }int mid=(l+r)>>1; if(x<=mid) update(lid,l,mid,x,y); if(y>mid) update(rid,mid+1,r,x,y); tr[now].sum=tr[lid].sum+tr[rid].sum; } int query(int now,int l,int r,int k) { if(l==r) return l; int mid=(l+r)>>1; if(tr[lid].sum>=k) return query(lid,l,mid,k); else return query(rid,mid+1,r,k-tr[lid].sum); } }st; signed main() { freopen("bubble.in","r",stdin); freopen("bubble.out","w",stdout); n=read(); for(int i=1;i<=n;i++) a[i]=read(),pos[a[i]]=i; q=read(); for(int i=1;i<=n;i++) { rev[i]=st1.query(n)-st1.query(a[i]); st1.update(a[i]); } int mxk=0,tot=0; for(int i=1;i<=q;i++) { int kk=read(),xx=read(); int p=pos[xx]; if(rev[p]>=kk) ans[i]=p-kk; else if(n<xx+kk) ans[i]=xx; else { op[++tot].k=kk,op[tot].x=xx,op[tot].id=i; } } sort(op+1,op+1+tot); int now=n+1; for(int i=1;i<=tot;i++) { while(now>1&&now-1>op[i].x) { now--; st.update(1,1,n,pos[now],pos[now]); } ans[op[i].id]=st.query(1,1,n,op[i].k)-op[i].k; } for(int i=1;i<=q;i++) cout<<ans[i]<<"\n"; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!