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\) 连边时,子树中的方案数。考虑枚举 \(x\) 在 \(G\) 中的父亲具体是哪一个,有转移:
然后在统计时用前缀和优化即可。
C 摸鱼军训
可算是搞懂了。
首先,我们需要确定一个数在 \(k\) 次冒泡排序后的位置,有以下几种可能:
-
第 \(k\) 次排序后前面仍有比他大的数;
-
没有比他大的数
-
他已经不会再移动(前缀已经有序)
首先,有几个比较重要的引理:
若 \(x\) 后方有 \(k\) 个小于它的数,第 \(k+1\) 个数大于它,那么本次移动 \(x\) 和下一个大于 \(x\) 的数中间的数都会移动到 \(x\) 前方。
证明:
我们设小于 \(x\) 的数为 \(p_1,p_2...p_k\),大于 \(x\) 的数为 \(q_1,q_2,...q_k\)
假设一次排序前的序列为 \(x,p_1,p_2,p_3,q_1,p_4,q_3\),那么显然,\(x\) 会与 \(p_1\) 交换,然后指针依然在 \(x\) 上,会与 \(p_2\) 交换,直到 \(q_1\) 为止。而接下来 \(p_4\) 会从 \(q_1\) 和 \(q_2\) 中间移动到 \(x\) 和 \(q_1\) 中间,以此类推。
若 \(x\) 前方已无大于它的数,且保证接下来的序列一定会变,那连续 \(k\) 次排序,第 \(i\) 次排序后 \(x\) 应该距离 \(p_i\) 在序列中的原位置有 \(i\) 长度。
证明:
我们已知一次排序后 \(x\) 会处在某个大于它的数的前面,那么根据上面的结论,第 \(i\) 次排序会使 \(q_{i-1}\) 和 \(q_i\) 中间的所有 \(p\) 移动到 \(q_{i-2}\) 和 \(q_{i-1}\) 中间,
此时,我们假设序列中没有 \(<x\) 的数,那排序到 \(k\) 次时确实距离 \(p_k\) 为 \(i\)。
那现在有了 \(<x\) 的数,原序列中 \(p_k\) 前面的、\(<x\) 的数来到了 \(x\) 的前方,假设有 \(m\) 个,
我们不关心 \(p_k\) 后方的数产生的影响,因为在 \(k\) 次后它们到不了 \(x\) 的前面,即对 \(x\) 现在的位置没有影响。
假设原序列中 \(x\) 到 \(p_k\) 的距离为 \(k+m\),即有 \(k\) 个大于 \(x\) 的,\(m\) 个小于 \(x\) 的,
那么既然那 \(m\) 个 \(<x\) 的数已然来到 \(x\) 前方,所以 \(x\) 到 \(q_k\) 的原位置不就是 \(k+m-m\),那不就是 \(k\) 吗。
情况 \(1\):
若 \(x\) 前面仍有大于它的数,那距离 \(x\) 最近的、大于 \(x\) 的数一定会移动到 \(x\) 后方。证明可看引理 1。
那么,有 \(i\) 个大于 \(x\) 的数,就一定需要 \(i\) 轮去把它们移动到 \(x\) 后方。并且,每移动一轮,\(x\) 的位置都会 \(-1\)。
因为有一个在它前面的大于它的数到了后面,且只有一个,所以会 \(-1\)。
记原序列中在位置 \(p\) 前方且大于 \(a_p\) 的数的个数为 \(rev_p\),那么对于所有 \(k\le rev_p\) 的轮,\(a_p\) 的位置一定是 \(p-k\)。
情况 \(2\):
此时,\(x\) 的前方已经没有比它大的数了,那我们根据引理 2,在第 \(k\) 轮,\(x\) 到 \(p_k\) 原位置的距离为 \(k\),只需要维护所有大于 \(x\) 的数的位置,并且找第 \(k\) 大的,那么本次排序后 \(x\) 的位置就是 \(pos_{p_k}-k\) 了。
情况 \(3\):
在第 \(i\) 轮,编号为 \(n-i+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;
}
浙公网安备 33010602011771号