【codeforces 749E】 Inversions After Shuffle
http://codeforces.com/problemset/problem/749/E (题目链接)
题意
给出一个1~n的排列,从中等概率的选取一个连续段,设其长度为l。对连续段重新进行等概率的全排列,求排列后整个原序列的逆序对的期望个数。
Solution
考虑对于每一对数${(a_i,a_j),i<j}$算贡献。
1.连续段包含${a_i,a_j}$
不妨设${a_i<a_j}$,则只有当排列后${a_j}$再${a_i}$前面才会对答案有贡献(${a_i>a_j}$的情况同理),连续段长度为${l}$。
于是满足${a_i}$在${a_j}$前面的排列数为${P_l^{l-2}}$,概率:${\frac{P_l^{l-2}}{P_l^l}=\frac{1}{2}}$。
满足包含${a_i}$和${a_j}$的连续段有${i*(n-j+1)}$个,其概率为:${\frac{2*i*(n-j+1)}{n*(n+1)}}$。
所以其期望等于两个概率相乘:
$${q_{i,j}=\frac{i*(n-j+1)}{n*(n+1)}}$$
这是${O(n^2)}$的,考虑优化。总期望:
$${Q=\sum_{i=1}^n \sum_{j=i+1}^n q_{i,j}}$$
$${Q=\sum_{i=1}^n \sum_{j=i+1}^n \frac{i*(n-j+1)}{n*(n+1)}}$$
发现${(n-j+1)}$是连续的,于是就变成了:
$${Q=\sum_{i=1}^n \frac {i*(n-i)*(n-i+1)} {2*n*(n+1)}}$$
这样复杂度就是${O(n)}$的了。
2.连续段不同时包含${a_i,a_j}$
如果${a_i<a_j}$,那么因为不被连续段同时包含,它们不会有机会改变相对位置,所以不会对答案做出贡献。考虑${a_i>a_j}$的情况。
那么连续段可能取到的区间有:${[1,j-1],[i+1,n]}$。考虑到区间${[i+1,j-1]}$被算了2次,容斥一下,所以区间的概率:
$${P_{i,j}=\frac {(j-1)*j+(n-i)*(n-i+1)-(j-i-1)*(j-i)} {n*(n+1)}}$$
$${P_{i,j}=\frac {(n^2+n)-(2*i+2*n*i)+2*i*j} {n*(n+1)}}$$
这个${P_{i,j}}$怎么快速求解呢,考虑逆序对这个东西。
$${Q=\sum_{i=1}^n \sum_{j=i+1}^n \frac {(n^2+n)-(2*i+2*n*i)+2*i*j} {n*(n+1)}}$$
设满足${a_j<a_i,j>i}$的${a_j}$的个数为${x}$,显然${x}$我们可以通过树状数组用求逆序对的方法${O(nlogn)}$的求出来,则:
$${Q=\sum_{i=1}^n \frac {x*((n^2+n)-(2*i+2*n*i)) + \sum_{j=i+1}^n 2*i*j} {n*(n+1)}}$$
那么现在${\sum_{j=i+1}^n 2*i*j}$怎么求呢。把${2*i}$提出去,那么就成了${2*i*\sum_{j=i+1}^n j}$我们用${y}$记录满足${a_j<a_i,j>i}$的${a_j}$的位置的和,也就是${\sum_{j=i+1}^n j}$,那么显然这个东西我们也是可以通过树状数组用求逆序对的方法${O(nlogn)}$的算出来的。则:
$${Q=\sum_{i=1}^n \frac {x*((n^2+n)-(2*i+2*n*i)) + 2*i*y} {n*(n+1)}}$$
于是问题就${O(nlogn)}$的解决了。
细节
mdzz不晓得哪里爆掉了还是精度问题,调了2天,最后莫名AC。。。
代码
// codeforces 749E
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=100010;
LL c[maxn],s[maxn],n;
int a[maxn];
long double ans; int lowbit(int x) {
return x&-x;
}
void add(LL *c,int x,LL val) {
for (int i=x;i<=n;i+=lowbit(i)) c[i]+=val;
}
LL query(LL *c,int x) {
LL res=0;
for (int i=x;i;i-=lowbit(i)) res+=c[i];
return res;
} void solve1() { //区间包含
long double Q=0;
for (LL i=1;i<=n;i++)
Q+=(long double)(i*(n-i)*(n-i+1))/2/n/(n+1);
ans+=Q;
}
void solve2() { //区间不包含
long double Q=0;
for (int i=n;i>=1;i--) {
LL x=query(c,a[i]-1);
Q-=(long double)(x*((2*i+2*n*i)-(n*n+n)))/n/(n+1);
Q+=(long double)(2*i)/n/(n+1)*query(s,a[i]-1);
add(c,a[i],1);
add(s,a[i],i);
}
ans+=Q;
}
int main() {
scanf("%lld",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
solve1();
solve2();
printf("%.20Lf",ans);
return 0;
}
贴一个暴力,供参考:
// codeforces 749E
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=100010;
LL c[maxn],s[maxn],n;
int a[maxn];
long double ans; int main() {
freopen("aaa.in","r",stdin);freopen("ccc.out","w",stdout);
scanf("%lld",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (LL i=1;i<=n;i++)
ans+=(long double)(i*(n-i)*(n-i+1))/(2*n*(n+1));
long double res=0;
for (LL i=n;i>=1;i--) {
for (LL j=i+1;j<=n;j++)
if (a[i]>a[j]) res+=(long double)((j-1)*j+(n-i)*(n-i+1)-(j-i-1)*(j-i))/(n*(n+1));
}
ans+=res;
printf("%.20Lf",ans);
return 0;
}
【codeforces 749E】 Inversions After Shuffle的更多相关文章
- 【codeforces 415D】Mashmokh and ACM(普通dp)
[codeforces 415D]Mashmokh and ACM 题意:美丽数列定义:对于数列中的每一个i都满足:arr[i+1]%arr[i]==0 输入n,k(1<=n,k<=200 ...
- 【codeforces 707E】Garlands
[题目链接]:http://codeforces.com/contest/707/problem/E [题意] 给你一个n*m的方阵; 里面有k个联通块; 这k个联通块,每个连通块里面都是灯; 给你q ...
- 【codeforces 707C】Pythagorean Triples
[题目链接]:http://codeforces.com/contest/707/problem/C [题意] 给你一个数字n; 问你这个数字是不是某个三角形的一条边; 如果是让你输出另外两条边的大小 ...
- 【codeforces 709D】Recover the String
[题目链接]:http://codeforces.com/problemset/problem/709/D [题意] 给你一个序列; 给出01子列和10子列和00子列以及11子列的个数; 然后让你输出 ...
- 【codeforces 709B】Checkpoints
[题目链接]:http://codeforces.com/contest/709/problem/B [题意] 让你从起点开始走过n-1个点(至少n-1个) 问你最少走多远; [题解] 肯定不多走啊; ...
- 【codeforces 709C】Letters Cyclic Shift
[题目链接]:http://codeforces.com/contest/709/problem/C [题意] 让你改变一个字符串的子集(连续的一段); ->这一段的每个字符的字母都变成之前的一 ...
- 【Codeforces 429D】 Tricky Function
[题目链接] http://codeforces.com/problemset/problem/429/D [算法] 令Si = A1 + A2 + ... + Ai(A的前缀和) 则g(i,j) = ...
- 【Codeforces 670C】 Cinema
[题目链接] http://codeforces.com/contest/670/problem/C [算法] 离散化 [代码] #include<bits/stdc++.h> using ...
- 【codeforces 515D】Drazil and Tiles
[题目链接]:http://codeforces.com/contest/515/problem/D [题意] 给你一个n*m的格子; 然后让你用1*2的长方形去填格子的空缺; 如果有填满的方案且方案 ...
随机推荐
- ArcGIS Engine开发之地图文档保存
在对地图文档进行修改后,经常需要对其进行保存.地图文档的保存有直接保存和另存为两种方式.这里的地图文档的修改指的是修改地图文档文件记录信息,不是对空间数据的编辑. 1.地图文档保存 具体实现的思路: ...
- SQL优化技术分析-1:操作符优化
1.IN 操作符 用IN写出来的SQL的优点是比较容易写及清晰易懂,这比较适合现代软件开发的风格.但是用IN的SQL 性能总是比较低的,从Oracle执行的步骤来分析用IN的SQL与不用IN的SQL有 ...
- 【mysql】关于binlog格式
写在前面的话 1.推荐用mixed,默认使用statement,基于上下文 set session/global binlog_format=mixed; 2.二进制日记录了数据库执行更改的操作,如 ...
- 光盘 iso 镜像制作相关命令操作
1. 安装制作工具 mkisofs yum install mkisofs -y 2. Linux 操作系统镜像 iso 打包 mkisofs -o /root/.iso \ -V mini7 -b ...
- ubuntu安装pppoeconf后与networkmanager冲突
使用pppoeconf拨号后,Network Manager显示设备未托管的解决办法: 在终端中输入以下命令,来配置网络连接管理文件: sudo gedit /etc/NetworkManager/n ...
- Java实现office文档与pdf文档的在线预览功能
最近项目有个需求要java实现office文档与pdf文档的在线预览功能,刚刚接到的时候就觉得有点难,以自己的水平难以在三四天做完.压力略大.后面查找百度资料.以及在同事与网友的帮助下,四天多把它做完 ...
- codevs 1285 二叉查找树STL基本用法
C++STL库的set就是一个二叉查找树,并且支持结构体. 在写结构体式的二叉查找树时,需要在结构体里面定义操作符 < ,因为需要比较. set经常会用到迭代器,这里说明一下迭代器:可以类似的把 ...
- Linux文本查看及处理.md
cat cat命令的用途是连接文件或标准输入并打印.这个命令常用来显示文件内容,或者将几个文件连接起来显示,或者从标准输入读取内容并显示,它常与重定向符号配合使用. 主要功能 一次显示整个文件:cat ...
- ActiveMQ笔记(6):消息延时投递
在开发业务系统时,某些业务场景需要消息定时发送或延时发送(类似:飞信的短信定时发送需求),这时候就需要用到activemq的消息延时投递,详细的文档可参考官网说明,本文只介绍二种常用的用法: 注:本文 ...
- mysql中间件atlas配置使用
MySQL所在机器: 192.168.16.70(Master) 192.168.16.74(Slave) 192.168.16.72(atlas)注意:主从复制需要自行配置atlas配置使 ...