codeforces 540E"Infinite Inversions"
题意:
给你一个无限大的整数序列 p = {1, 2, 3, ...};
有 n 次操作,每次操作交换第 ai 个数和第 aj 个数;
求序列中逆序对的个数;
题解:
考虑交换完后的序列,存在连续的区间 [ i , j ] 使得 p[ i ] = i , 那么分下一下这种区间的特点
假设 i 之前有 x 个数大于 p[ i ],那么可知对于第 i 个数有 x 个逆序对,同理,因为 p[ i+1 ] = p[ i ]
所以 i+1 之前也一定有且只有 x 个数大于 p[ i+1 ],那么第 i+1 个数也有 x 个逆序对,那么对于连续的区间[i,j]
易的区间 [ i , j ] 与其之前的数可构成的逆序对的个数为 (j-i+1)*x 个,那么可将其映射为一个值 i ,并记录其有 (j-i+1) 个数;
例如,假设 n 次操作为
1 4
1 8
那么交换完后,前 8 个数的排列状况为:
1 2 3 4 5 6 7 8
8 2 3 1 5 6 7 4
那么可得区间 [2,3] 和区间[5,6]的值未发生改变,当然区间[9,+∞]也为发生改变,但[9,+∞]并不影响答案,所以不用考虑。
那么根据之前提到的,将为改变的大区间映射到某个值身上,并记录有多少数映射到这个值上了,如下所示:
1 2 3 4 5
8 1 4
映射完后,区间[2,3]合并到了2上,区间[5,7]合并到了5上,接下来就是求映射完后的数组的逆序对总个数,这就变成了经典的
树状数组求逆序对个数的题了。
这就完事了么????当然不是~~~
考虑 4 这个值,其之前的 5 只给 4 提供了一个逆序对,但实际上 6,7 也会提供,那么这就少算了两个逆序对数,这该怎么办呢?
考虑某个区间 [i , j],一共有 j-i+1 个数,易得区间 [ i , j ] 只会影响其之后且值小于 i 的数,那么就再用一次树状数组,如果来到了某个
映射的值,那么将 i 之后的数通过树状数组 +(j-i),对于某个在其之后且值小于 i 的数 x ,直接在答案上额外加上 Sum(x+1)即可。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
#define lowbit(x) (x&-x)
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=1e6+; int n;
map<int,int>f;//记录交换后的序列状况
int diff[maxn];
int sum[maxn];
struct Date
{
int val;
int id;//初始编号
int tot;//如果某个区间映射到值val上,那么tot记录的就是区间的总个数
int newVal;//离散后的值
Date(int val=,int id=,int tot=):val(val),id(id),tot(tot){}
}_date[maxn]; struct BIT
{
int bit[maxn];
void Init()
{
mem(bit,);
}
void Add(int t,int x,int k)
{
while(t <= k)
{
bit[t] += x;
t += lowbit(t);
}
}
int Sum(int t)
{
int sum=;
while(t > )
{
sum += bit[t];
t -= lowbit(t);
}
return sum;
}
}_bit; bool cmp1(Date a,Date b)
{
return a.val < b.val;
}
bool cmp2(Date a,Date b)
{
return a.id < b.id;
} int Trans()
{
map<int,int>::iterator it;
int index=;
int preIndex=f.begin()->first;
int nexIndex; for(it=++f.begin();it != f.end();++it)
{
_date[++index]=Date(f[preIndex],index,);
nexIndex=it->first; //判断是否为未改变的区间
int tot=nexIndex-preIndex-;
if(tot >= )
_date[++index]=Date(preIndex+,index,tot); preIndex=nexIndex;
}
_date[++index]=Date(f[preIndex],index,); sort(_date+,_date+index+,cmp1);//按其val由小到大排序,方便离散化
for(int i=;i <= index;++i)
_date[i].newVal=i;//离散化
sort(_date+,_date+index+,cmp2);//按 id 从小到大复原 return index;
} ll Solve()
{
//离散化
int index=Trans();
_bit.Init();//树状数组初始化
ll ans=; //经典树状数组求逆序对个数
for(int i=;i <= index;++i)
{
int x=_date[i].newVal;
_bit.Add(x,,index);
ans += 1ll*(i-_bit.Sum(x))*_date[i].tot;
} //求解区间少加的逆序对个数
_bit.Init();
for(int i=;i <= index;++i)
{
int x=_date[i].newVal;
_bit.Add(x,_date[i].tot-,index);//只有 tot > 1才会加入到树状数组中 //求解 i 前值 > x 的未改变的区间少加的数的总个数
if(_date[i].tot == )
ans += _bit.Sum(index)-_bit.Sum(x); } return ans;
}
int main()
{
// freopen("C:/Users/hyacinthLJP/Desktop/stdin/contest","r",stdin);
scanf("%d",&n);
for(int i=;i <= n;++i)
{
int a,b;
scanf("%d%d",&a,&b);
int x,y;
x=(!f.count(a) ? a:f[a]);
y=(!f.count(b) ? b:f[b]); f[a]=y;
f[b]=x;
}
printf("%I64d\n",Solve()); return ;
}
codeforces 540E"Infinite Inversions"的更多相关文章
- CodeForces 540E - Infinite Inversions(离散化+树状数组)
花了近5个小时,改的乱七八糟,终于A了. 一个无限数列,1,2,3,4,...,n....,给n个数对<i,j>把数列的i,j两个元素做交换.求交换后数列的逆序对数. 很容易想到离散化+树 ...
- Codeforces Round #301 (Div. 2) E . Infinite Inversions 树状数组求逆序数
E. Infinite Inversions ...
- CF #301 E:Infinite Inversions(逆序数,树状数组)
A-Combination Lock B-School Marks C-Ice Cave D-Bad Luck Island E-Infinite Inversions E:Infini ...
- 线段树 离散化 E. Infinite Inversions E. Physical Education Lessons
题目一:E. Infinite Inversions 这个题目没什么思维量,还比较简单,就是离散化要加上每一个值的后面一个值,然后每一个值放进去的不是1 ,而是这个值与下一个点的差值. 因为这个数代表 ...
- codeforces 301 E. Infinite Inversions
题目: time limit per test 2 seconds memory limit per test 256 megabytes input standard input output ...
- 【Codeforces Round #301 (Div. 2) E】Infinite Inversions
[链接] 我是链接,点我呀:) [题意] 给你一个无限长的序列1,2,3,4... 然后给你n个操作. 每个操作ai,bi; 表示调换位置为ai和位置为bi的数的位置. (ai,bi<=10^9 ...
- Infinite Inversions(树状数组+离散化)
思路及代码参考:https://blog.csdn.net/u014800748/article/details/45420085 There is an infinite sequence cons ...
- 【codeforces 749E】 Inversions After Shuffle
http://codeforces.com/problemset/problem/749/E (题目链接) 题意 给出一个1~n的排列,从中等概率的选取一个连续段,设其长度为l.对连续段重新进行等概率 ...
- codeforces 622A Infinite Sequence
A. Infinite Sequence time limit per test 1 second memory limit per test 256 megabytes input standard ...
随机推荐
- mysql group by 对多个字段进行分组
在平时的开发任务中我们经常会用到MYSQL的GROUP BY分组, 用来获取数据表中以分组字段为依据的统计数据.比如有一个学生选课表,表结构如下: Table: Subject_Selection S ...
- 使用@Validated分组遇到的坑
在使用@Validate注解分组校验时,如果指定分组,所有的需要验证的属性都必须添加指定分组才会校验 解决办法: 没有指明分组的属性都属于Default,所以分组接口继承Default就可以解决
- [离散时间信号处理学习笔记] 3. 一些基本的LTI系统
首先我们需要先对离散时间系统进行概念上的回顾: $y[n] = T\{ x[n] \}$ 上面的式子表征了离散时间系统,也就是把输入序列$x[n]$,映射称为$y[n]$的输出序列. 不过上述式子也可 ...
- BZOJ3812 主旋律(状压dp+容斥原理)
设f[S]为S点集是SCC的方案数.考虑通过去掉不合法方案转移.可以枚举入度为0的SCC所含点集S',这样显然S^S'内部的边和由S'连向S^S'的边删还是不删任选.但是这样无法保证S'包含所有入度为 ...
- BZOJ5475 WC2019数树(prufer+容斥原理+树形dp+多项式exp)
因为一大堆式子实在懒得写题解了.首先用prufer推出CF917D用到的结论,然后具体见前言不搭后语的注释. #include<iostream> #include<cstdio&g ...
- 第十九天 标准目录与time 模块
今日内容 1.目录规范 ***** (1)文件夹的规范写法 bin 可执行文件 conf 配置文件 core 主要业务逻辑 db 数据文件 lib 库 (公共代码 第三方模块) log 日志文件 ...
- 洛谷P2084 进制转换
题目背景 无 题目描述 今天小明学会了进制转换,比如(10101)2 ,那么它的十进制表示的式子就是 : 1*2^4+0*2^3+1*2^2+0*2^1+1*2^0, 那么请你编程实现,将一个M进制的 ...
- HYSBZ1036-树链剖分-点权
树链剖分,点权,单点更改,路径查询.学树链剖分下面这个博文不错 http://blog.csdn.net/y990041769/article/details/40348013 线段树必须写的很熟练才 ...
- LOJ6436 [PKUSC2018] 神仙的游戏 【FFT】
题目分析: 题目要求前后缀相同,把串反过来之后是一个很明显的卷积的形式.这样我们可以完成初步判断(即可以知道哪些必然不行). 然后考虑一下虽然卷积结果成立,但是存在问号冲突的情况. 箭头之间应当不存在 ...
- 【UOJ347】【WC2018】通道 边分治 虚树 DP
题目大意 给你三棵树,点数都是\(n\).求 \[ \max_{i,j}d_1(i,j)+d_2(i,j)+d_3(i,j) \] 其中\(d_k(i,j)\)是在第\(k\)棵数中\(i,j\)两点 ...