[xsy 2669][樹狀陣列][組合數]歸併排序
阿新 • • 發佈:2018-12-06
題目描述
有一個長度為n的排列
,你要把這個陣列歸併排序。但是在長度為2的時候有
的概率會把兩個數交換(就是有
的概率返回錯的結果)。有兩種操作
1:交換兩個數
2:詢問排序後的一個位置等於一個數的概率。
solution
考慮相鄰的兩個數a,b(
)
若交換後a排在b後面,則a在接下來的歸併排序可以視為b+0.5
即a會始終"粘"著b
即a可能的"值"為
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;
}