[ICPC 2022 WF] Doing the Container Shuffle 题解
请注意文中“堆栈”和“卡车”的区别。
仔细分析一下这个调整栈顶的过程,根据期望的线性性,发现可以对于“每一段”过程分开计算:对于集装箱
先考虑怎样的集装箱可能会在这个过程中被调整:只有
接下来将证明每个满足以上条件的集装箱
- 若
a_j<a_{i+1} (概率为\frac{1}{2} ),即a_j 在a_{i+1} 之前被装入堆栈:- 若
a_j 被装入堆栈1 ,a_{i+1} 不管怎么放都会使a_j 位于两者中间,概率为\frac{1}{2}\times\frac{1}{2}=\frac{1}{4} ; - 否则
a_{i+1} 不管怎么放都不会使a_j 位于两者中间;
- 若
- 若
a_j>a_{i+1} (概率为\frac{1}{2} ),即a_j 在a_{i+1} 之后被装入堆栈:- 若
a_{i+1} 被装入堆栈2 ,a_j 不管怎么放都会位于两者中间,概率为\frac{1}{2}\times\frac{1}{2}=\frac{1}{4} ; - 否则
a_j 不管怎么放都不会位于两者中间。
- 若
综上每个满足条件集装箱会在该过程中被调整的概率是
别忘了计算第一步移动时
放代码:
#include<bits/stdc++.h>
using namespace std;
namespace IAOI_lib{
template<typename T> class fenwick_tree{
private:
vector<T> t;
public:
fenwick_tree(int n):t(n){}
int lowbit(int x){
return x&-x;
}
void add(int p,T d){
t[p++]+=d;
while((p+=lowbit(p))<=t.size())t[p-1]+=d;
}
T pre_sum(int p){
T s=t[p++];
while((p-=lowbit(p))>0)s+=t[p-1];
return s;
}
T sum(int l,int r){
return pre_sum(r)-(l?pre_sum(l-1):0);
}
}; // 树状数组模板
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n; long long c=0; cin>>n;
vector<int> a(n);
for(auto &i:a)cin>>i,i--;
IAOI_lib::fenwick_tree<int> t(n);
for(int i=n-1;i;i--)
t.add(a[i],1),c+=t.sum(min(i>1?a[i-2]:n,a[i-1])+1,n-1);
// 按照文中所述方法统计答案
cout<<(c>>1)+n<<(c&1?".5":"")<<endl;
return 0;
}