题目大意
给定一个
n
的排列
∙
对这个排列进行一个有bug的归并排序:在分治到长度为
2
时会以
答案对
1≤n≤216,1≤q≤105
题目分析
观察发现,出现bug的时候,较小的那个数在排完序之后一定在较大那个数的后一位置。因此我们将出现bug的情况看成较小的数变成较大的数
+0.5
显然是等价的。
然后问题就可以变成
n
个数,每个数有两种等概率的取值,数与数之间取值互相独立,并且两个不同的数不会有相同的取值,求某个数排完序之后排名为
先考虑怎么做询问,我枚举这个数的取值,然后相当于我要求恰好有
y−1
个数排完序小于它。我们可以求出一定小于它的数的个数以及有
1/2
概率小于它的数的个数,然后组合数算一算。
然后这个个数怎么统计呢?其实就是一个二维数点的问题,因为要支持修改,因此我们可以考虑使用嵌套数据结构或者定期重构的KD-tree来解决,时间复杂度在
O(nlog2n)
或
O(nn√)
左右,不是特别优秀。
怎么优化时间呢?可以发现这题的点有特殊性质,就是它
x
坐标一定小于等于
代码实现
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cctype>
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
int buf[30];
void write(int x)
{
if (x<0) putchar('-'),x=-x;
for (;x;x/=10) buf[++buf[0]]=x%10;
if (!buf[0]) buf[++buf[0]]=0;
for (;buf[0];putchar('0'+buf[buf[0]--]));
}
const int itwo=500000004;
const int P=1000000007;
const int N=1<<18;
int lowbit(int x){return x&-x;}
int quick_power(int x,int y)
{
int ret=1;
for (;y;y>>=1,x=1ll*x*x%P) if (y&1) ret=1ll*ret*x%P;
return ret;
}
int fact[N],invf[N],POW[N],rg[N][2];
int a[N];
int n,q,d,lim;
int C(int n,int m){return 1ll*fact[n]*invf[m]%P*invf[n-m]%P;}
struct Fenwick_tree
{
int v[N];
void modify(int x,int delta){for (;x<=lim;x+=lowbit(x)) v[x]+=delta;}
int query(int x)
{
int ret=0;
for (;x;x-=lowbit(x)) ret+=v[x];
return ret;
}
}t[2];
void ADD(int x){t[0].modify(rg[x][0],1),t[1].modify(rg[x][1],1);}
void DEL(int x){t[0].modify(rg[x][0],-1),t[1].modify(rg[x][1],-1);}
void pre()
{
d=quick_power(quick_power(2,n),P-2);
fact[0]=1;
for (int i=1;i<=n;++i) fact[i]=1ll*fact[i-1]*i%P;
POW[0]=1;
for (int i=1;i<=n;++i) POW[i]=1ll*POW[i-1]*itwo%P;
invf[n]=quick_power(fact[n],P-2);
for (int i=n;i>=1;--i) invf[i-1]=1ll*invf[i]*i%P;
for (int i=0;i<n;++i)
if (a[i]>a[i^1]) rg[i][0]=rg[i][1]=(a[i]<<1)-1;
else rg[i][0]=(a[i]<<1)-1,rg[i][1]=a[i^1]<<1;
for (int i=0;i<n;++i) ADD(i);
}
int calc(int x,int y)
{
int cnt=t[1].query(x-1),cnt_=t[0].query(x)-1;
return cnt>y?0:1ll*C(cnt_-cnt,y-cnt)*POW[cnt_-cnt]%P;
}
int main()
{
freopen("sort.in","r",stdin),freopen("sort.out","w",stdout);
lim=(n=read())<<1;
for (int i=0;i<n;++i) a[i]=read();
pre();
for (q=read();q--;)
{
int opt=read(),x=read()-1,y=read()-1;
if (opt==1)
{
if (x==y) continue;
DEL(x),DEL(x^1);
if ((x|1)!=(y|1)) DEL(y),DEL(y^1);
swap(a[x],a[y]);
if (a[x]>a[x^1]) rg[x][0]=rg[x][1]=(a[x]<<1)-1,rg[x^1][0]=(a[x^1]<<1)-1,rg[x^1][1]=a[x]<<1;
else rg[x][0]=(a[x]<<1)-1,rg[x][1]=a[x^1]<<1,rg[x^1][0]=rg[x^1][1]=(a[x^1]<<1)-1;
if (x|1!=y|1) if (a[y]>a[y^1]) rg[y][0]=rg[y][1]=(a[y]<<1)-1,rg[y^1][0]=(a[y^1]<<1)-1,rg[y^1][1]=a[y]<<1;
else rg[y][0]=(a[y]<<1)-1,rg[y][1]=a[y^1]<<1,rg[y^1][0]=rg[y^1][1]=(a[y^1]<<1)-1;
ADD(x),ADD(x^1);
if ((x|1)!=(y|1)) ADD(y),ADD(y^1);
}
else
{
int ans=1ll*(calc(rg[x][0],y)+calc(rg[x][1],y))*itwo%P;
write(ans),putchar('\n');
}
}
fclose(stdin),fclose(stdout);
return 0;
}