题目描述

  有一个长度为\(n\)的排列\(n=2^k\),你要把这个数组归并排序。但是在长度为\(2\)的时候有\(\frac{1}{2}\)的概率会把两个数交换(就是有\(\frac{1}{2}\)的概率返回错的结果)。有两种操作

  \(1\):交换两个数

  \(2\):询问排序后的一个位置等于一个数的概率。

  \(k\leq 16,q\leq {10}^5\)

题解

  这个排序有点奇怪。两个数\(a,b(a<b)\)排序后可能是\(ab\)也可能是\(ba\)。

  观察到\(ab\)会正常排序,而\(ba\)中\(a\)会一直跟着\(b\),所以可以把\(a\)看成\(b+0.5\)。

  这样就会有一些数确定,有些数是两个数中的一个。

  用两个树状数组维护小的数和大的数不超过\(x\)的个数,每次询问用组合数乱搞即可。

  时间复杂度:\(O((n+q)\log n)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<cmath>
#include<functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void sort(int &a,int &b)
{
if(a>b)
swap(a,b);
}
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
int rd()
{
int s=0,c;
while((c=getchar())<'0'||c>'9');
do
{
s=s*10+c-'0';
}
while((c=getchar())>='0'&&c<='9');
return s;
}
void put(int x)
{
if(!x)
{
putchar('0');
return;
}
static int c[20];
int t=0;
while(x)
{
c[++t]=x%10;
x/=10;
}
while(t)
putchar(c[t--]+'0');
}
int upmin(int &a,int b)
{
if(b<a)
{
a=b;
return 1;
}
return 0;
}
int upmax(int &a,int b)
{
if(b>a)
{
a=b;
return 1;
}
return 0;
}
const ll p=1000000007;
ll fp(ll a,ll b)
{
ll s=1;
for(;b;b>>=1,a=a*a%p)
if(b&1)
s=s*a%p;
return s;
}
int n,a[100010];
int c1[200010];
int c2[200010];
void add(int *c,int x,int v)
{
for(;x<=2*n;x+=x&-x)
c[x]+=v;
}
int sum(int *c,int x)
{
int s=0;
for(;x;x-=x&-x)
s+=c[x];
return s;
}
int a1[100010];
int a2[100010];
int o(int x)
{
return ((x-1)^1)+1;
}
void add(int x,int v)
{
int y=o(x);
if(a[x]>a[y])
{
add(c1,2*a[x]-1,v);
add(c2,2*a[x]-1,v);
a1[x]=a2[x]=2*a[x]-1;
}
else
{
add(c1,2*a[x]-1,v);
add(c2,2*a[y],v);
a1[x]=2*a[x]-1;
a2[x]=2*a[y];
}
}
ll inv[100010];
ll fac[100010];
ll ifac[100010];
ll c(int x,int y)
{
if(x<y)
return 0;
if(y<0)
return 0;
return fac[x]*ifac[y]%p*ifac[x-y]%p;
}
ll query(int x,int y,int b=0)
{
ll ans=1;
x--;
y--;
int s1=sum(c2,y);
int s2=sum(c1,y)-s1;
if(b)
s2--;
ans=ans*c(s2,x-s1)%p*fp(inv[2],s2)%p;
return ans;
}
int main()
{
open("c");
scanf("%d",&n);
int i;
inv[0]=inv[1]=fac[0]=fac[1]=ifac[0]=ifac[1]=1;
for(i=2;i<=n;i++)
{
inv[i]=-p/i*inv[p%i]%p;
fac[i]=fac[i-1]*i%p;
ifac[i]=ifac[i-1]*inv[i]%p;
}
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=1;i<=n;i++)
add(i,1);
int q;
scanf("%d",&q);
int op,x,y;
for(i=1;i<=q;i++)
{
scanf("%d%d%d",&op,&x,&y);
if(op==1)
{
add(x,-1);
add(y,-1);
add(o(x),-1);
add(o(y),-1);
swap(a[x],a[y]);
add(x,1);
add(y,1);
add(o(x),1);
add(o(y),1);
}
else
{
ll ans;
if(a1[x]==a2[x])
ans=query(y,a1[x]);
else
ans=(query(y,a1[x])+query(y,a2[x],1))*inv[2]%p;
ans=(ans+p)%p;
printf("%lld\n",ans);
}
}
return 0;
}

【XSY2669】归并排序 树状数组 简单组合数学的更多相关文章

  1. 51nod1019逆序数(归并排序/树状数组)

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1019 题意:中文题诶- 思路: 方法1:归并排序- 归并排序过 ...

  2. 洛谷 P1908 逆序对 Label:归并排序||树状数组 不懂

    题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计.最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定 ...

  3. UVA 11990 `Dynamic'' Inversion CDQ分治, 归并排序, 树状数组, 尺取法, 三偏序统计 难度: 2

    题目 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&a ...

  4. POJ 3067 - Japan - [归并排序/树状数组(BIT)求逆序对]

    Time Limit: 1000MS Memory Limit: 65536K Description Japan plans to welcome the ACM ICPC World Finals ...

  5. 剑指 Offer 51. 数组中的逆序对 + 归并排序 + 树状数组

    剑指 Offer 51. 数组中的逆序对 Offer_51 题目描述 方法一:暴力法(双层循环,超时) package com.walegarrett.offer; /** * @Author Wal ...

  6. BZOJ-1227 虔诚的墓主人 树状数组+离散化+组合数学

    1227: [SDOI2009]虔诚的墓主人 Time Limit: 5 Sec Memory Limit: 259 MB Submit: 914 Solved: 431 [Submit][Statu ...

  7. POJ2299Ultra-QuickSort(归并排序 + 树状数组求逆序对)

    树状数组求逆序对   转载http://www.cnblogs.com/shenshuyang/archive/2012/07/14/2591859.html 转载: 树状数组,具体的说是 离散化+树 ...

  8. HDU 6318 Swaps and Inversions(归并排序 || 树状数组)题解

    题意:一个逆序对罚钱x元,现在给你交换的机会,每交换任意相邻两个数花钱y,问你最少付多少钱 思路:最近在补之前还没过的题,发现了这道多校的题.显然,交换相邻两个数逆序对必然会变化+1或者-1,那我们肯 ...

  9. 树状数组 简单题 cf 961E

    题目链接 : https://codeforces.com/problemset/problem/961/E One day Polycarp decided to rewatch his absol ...

随机推荐

  1. JS 面向对象 ~ 创建对象的 9 种方式

    一.创建对象的几种方式 1.通过字面量创建 var obj = {}; 这种写法相当于: var obj = new Object(); 缺点:使用同一个接口创建很多单个对象,会产生大量重复代码 2. ...

  2. 2017湘潭大学邀请赛G题(贪心+优先队列)

    参考博客:http://www.cnblogs.com/chendl111/p/6891770.html 题目链接:https://www.icpc.camp/contests/4mYguiUR8k0 ...

  3. Dubbo负载均衡与集群容错机制

    1  Dubbo简介 Dubbo是一款高性能.轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现. 作为一个轻量级RPC框架,D ...

  4. 怎么去掉Xcode工程中的某种类型的警告 Implicit conversion loses integer precision: 'NSInteger' (aka 'long') to 'int32

    unsigned long numComponents = CGColorGetNumberOfComponents([[UIColor blackColor] CGColor]); 2014年12月 ...

  5. JS典记

        var href = "";     //遍历a标签     $ ( "a"). each (function () {         href = ...

  6. react-router的坑

    componentWillReceiveProps(nextProps){ 在改钩子函数里接受组件变化的最近的传递的props 如果在这里没有使用nextprops 而是调用this.props 会出 ...

  7. C#设计模式之10:状态模式

    状态模式 状态模式将合适的Context(上下文)模拟成一个状态机,在这个状态机的内部,由Context来决定整个状态机的状态,再根据不同的状态执行不同的方法.在C#编译器的帮助下,很多语法糖的背后都 ...

  8. flutter-StatelessWidget与StatefulWidget

    StatelessWidget和StatefulWidget是flutter的基础组件,日常开发中自定义Widget都是选择继承这两者之一. 两者的区别在于状态的改变,StatelessWidget面 ...

  9. python爬虫之git的使用(windows下pycharm使用)

    相信很多同学学会了git或者github以后都不知道怎么跟windows上的pycharm连在一起工作,那么下面我们开始介绍简单的安装和使用方法. 一.安装 1.首先你的有一个github的账户.注册 ...

  10. 为linux主机增加file description

    在benchmarked写的服务器的时候就遇到了too many file open 这个报错. 由于遇到过很多次了,所以知道应该是单机fd打满了. 首先来看看 机器最多支持多少fd cat /pro ...