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 共轭树图

首先的结论,是 G 图是一棵树。

然后省略证明,然后考虑 dp:

f(x,i) 表示以 x 为根的子树,且 x 只允许与它的第 i 个祖先在 G 连边时,子树中的方案数。考虑枚举 xG 中的父亲具体是哪一个,有转移:

f(x,i)=j=1if(y,i(j1)+1)

然后在统计时用前缀和优化即可。

C 摸鱼军训

可算是搞懂了。

首先,我们需要确定一个数在 k 次冒泡排序后的位置,有以下几种可能:

  • k 次排序后前面仍有比他大的数;

  • 没有比他大的数

  • 他已经不会再移动(前缀已经有序)

首先,有几个比较重要的引理:

x 后方有 k 个小于它的数,第 k+1 个数大于它,那么本次移动 x 和下一个大于 x 的数中间的数都会移动到 x 前方。

证明:
我们设小于 x 的数为 p1,p2...pk,大于 x 的数为 q1,q2,...qk
假设一次排序前的序列为 x,p1,p2,p3,q1,p4,q3,那么显然,x 会与 p1 交换,然后指针依然在 x 上,会与 p2 交换,直到 q1 为止。而接下来 p4 会从 q1q2 中间移动到 xq1 中间,以此类推。

x 前方已无大于它的数,且保证接下来的序列一定会变,那连续 k 次排序,第 i 次排序后 x 应该距离 pi 在序列中的原位置有 i 长度。

证明:
我们已知一次排序后 x 会处在某个大于它的数的前面,那么根据上面的结论,第 i 次排序会使 qi1qi 中间的所有 p 移动到 qi2qi1 中间,
此时,我们假设序列中没有 <x 的数,那排序到 k 次时确实距离 pki
那现在有了 <x 的数,原序列中 pk 前面的、<x 的数来到了 x 的前方,假设有 m 个,
我们不关心 pk 后方的数产生的影响,因为在 k 次后它们到不了 x 的前面,即对 x 现在的位置没有影响。
假设原序列中 xpk 的距离为 k+m,即有 k 个大于 x 的,m 个小于 x 的,
那么既然那 m<x 的数已然来到 x 前方,所以 xqk 的原位置不就是 k+mm,那不就是 k 吗。

情况 1

x 前面仍有大于它的数,那距离 x 最近的、大于 x 的数一定会移动到 x 后方。证明可看引理 1

那么,有 i 个大于 x 的数,就一定需要 i 轮去把它们移动到 x 后方。并且,每移动一轮,x 的位置都会 1

因为有一个在它前面的大于它的数到了后面,且只有一个,所以会 1

记原序列中在位置 p 前方且大于 ap 的数的个数为 revp,那么对于所有 krevp 的轮,ap 的位置一定是 pk

情况 2:

此时,x 的前方已经没有比它大的数了,那我们根据引理 2,在第 k 轮,xpk 原位置的距离为 k,只需要维护所有大于 x 的数的位置,并且找第 k 大的,那么本次排序后 x 的位置就是 pospkk 了。

情况 3

在第 i 轮,编号为 ni+1 的数一定会被移动到最终位置。

点击查看代码
#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;
}

D 神奇园艺师

posted @   ccjjxx  阅读(16)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示