1. 程式人生 > >[xsy 2669][樹狀陣列][組合數]歸併排序

[xsy 2669][樹狀陣列][組合數]歸併排序

題目描述
  有一個長度為n的排列 n = 2 k n=2^k ,你要把這個陣列歸併排序。但是在長度為2的時候有 1

2 \frac{1}{2} 的概率會把兩個數交換(就是有 1 2 \frac{1}{2} 的概率返回錯的結果)。有兩種操作
  1:交換兩個數
  2:詢問排序後的一個位置等於一個數的概率。
k
16 , q 100000 k\leqslant16,q\leqslant 100000

solution
考慮相鄰的兩個數a,b( a

< b a<b )
若交換後a排在b後面,則a在接下來的歸併排序可以視為b+0.5
即a會始終"粘"著b
即a可能的"值"為 a , b + 0.5 a,b+0.5
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;
}