题目描述
有一个长度为n的排列
n
=
2
k
n=2^k
n=2k,你要把这个数组归并排序。但是在长度为2的时候有
1
2
\frac{1}{2}
21的概率会把两个数交换(就是有
1
2
\frac{1}{2}
21的概率返回错的结果)。有两种操作
1:交换两个数
2:询问排序后的一个位置等于一个数的概率。
k
⩽
16
,
q
⩽
100000
k\leqslant16,q\leqslant 100000
k⩽16,q⩽100000
solution
考虑相邻的两个数a,b(
a
<
b
a<b
a<b)
若交换后a排在b后面,则a在接下来的归并排序可以视为b+0.5
即a会始终"粘"着b
即a可能的"值"为
a
,
b
+
0.5
a,b+0.5
a,b+0.5
b可能的值为
b
,
b
b,b
b,b
每次查询相当于问有多少种取值方式,使得y-1个数小于它
分类讨论一下,树状数组+组合数即可
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int Mod=1000000007;
int n,q;
#define Maxn 100010
int a[Maxn];
int b[Maxn][2];
int Pow[Maxn];
int fact[Maxn],inv[Maxn];
inline int C(int i,int j){return 1ll*fact[i]*inv[i-j]%Mod*inv[j]%Mod;}
struct Bit{
int sum[Maxn<<1];
inline int lowbit(int x){return x&(-x);}
inline void Add(int x,int ad){
if(!x)return;
for(int i=x;i<=2*n+1;i+=lowbit(i))sum[i]+=ad;
}
inline int Query(int x){
int ans=0;
for(int i=x;i;i-=lowbit(i))ans+=sum[i];
return ans;
}
}T1,T2;//min max
inline void Modify(int x){
T1.Add(b[x][0],-1);T2.Add(b[x][1],-1);
T1.Add(b[x+1][0],-1);T2.Add(b[x+1][1],-1);
if(a[x]<a[x+1]){b[x][0]=2*a[x];b[x][1]=2*a[x+1]+1;b[x+1][0]=b[x+1][1]=2*a[x+1];}
else{b[x][0]=b[x][1]=2*a[x];b[x+1][0]=2*a[x+1];b[x+1][1]=2*a[x]+1;}
T1.Add(b[x][0],1);T2.Add(b[x][1],1);
T1.Add(b[x+1][0],1);T2.Add(b[x+1][1],1);
}
inline void rd(int &x){
x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
}
int main(){
rd(n);
for(register int i=1;i<=n;++i)rd(a[i]);
if(n==1){
rd(q);
while(q--)puts("1");
return 0;
}
for(register int i=1;i<n;i+=2)Modify(i);
int opt,x,y;
fact[0]=1;
for(register int i=1;i<=n;++i)fact[i]=1ll*fact[i-1]*i%Mod;
inv[0]=inv[1]=1;
for(register int i=2;i<=n;++i)inv[i]=1ll*(Mod-Mod/i)*inv[Mod%i]%Mod;
for(register int i=2;i<=n;++i)inv[i]=1ll*inv[i-1]*inv[i]%Mod;
Pow[0]=1;
for(register int i=1;i<=n;++i)Pow[i]=1ll*Pow[i-1]*inv[2]%Mod;
rd(q);
while(q--){
rd(opt);rd(x);rd(y);
if(opt==1){
swap(a[x],a[y]);
if(x&1)Modify(x);
else Modify(x-1);
if(y&1)Modify(y);
else Modify(y-1);
}else{
int Ans=0;
int ans1=T1.Query(b[x][0]-1);
int ans2=T2.Query(b[x][0]-1);
if(ans2<y&&ans1>=y-1)Ans=(Ans+1ll*C(ans1-ans2,y-1-ans2)*Pow[ans1-ans2+1])%Mod;
ans1=T1.Query(b[x][1]-1);if(b[x][1]>b[x][0])ans1--;
ans2=T2.Query(b[x][1]-1);
if(ans2<y&&ans1>=y-1)Ans=(Ans+1ll*C(ans1-ans2,y-1-ans2)*Pow[ans1-ans2+1])%Mod;
printf("%d\n",Ans);
}
}
return 0;
}