Codeforces 414C Mashmokh and Reverse Operation 归并排序在线求交换序列后逆序数

来源:互联网 发布:socket 网络调试工具 编辑:程序博客网 时间:2024/04/29 23:15

题目链接:http://codeforces.com/contest/414/problem/C

先复制一个思路:

解法:2^n个数,可以联想到建立一棵二叉树的东西,比如  2,1,4,3就可以建成下面这样

                                                    [2,1,4,3]                        level 2

                                                   /               \

                                              [2,1]              [4,3]                  level 1

                                           /        \              /     \

                                        [2]         [1]        [4]    [3]              level 0

然后算某个区间的逆序数的时候[2,1,4,3]实际上就是算[2,1],[4,3]的逆序数再加上[2,1],[4,3]之间的逆序数,思路和归并排序是一样的。

然后我们看下每次翻转,假如我们分成2^k份,我们会发现,对于level k+1层以上的逆序数是不会改变的,但是level k~level 0的逆序数对会翻转,我们只需要知道level k~level 0各个区间翻转后的逆序数就可以了。 


题意:

给定 2^n 长的序列 

下面que个询问,对于每个询问 u,

1、先把 序列分段分成: [0, 2^u-1], [2^u, 2^(u+1)-1],······

2、再把每段都翻转一下。 

3、输出此时序列的逆序数。


思路:首先我们要得到:

对于一个序列[l,r) 的翻转 =

1、 将该序列的[l,mid), [mid,r)}交换 

 2、[l,mid/2),[mid/2,mid)交换 + [mid,mid+mid/2),[mid+mid/2,r) 交换

 3、 如此递归下去

例如:12345678-> 87654321

等价于 1234 | 5678 -> 5678 | 1234 -> 7856 | 3412 -> 8765 | 4321


于是把序列分层,得到n层

对于每一层[l, r] 的逆序数对分为:

1、两个数字都在[l,mid) 内的 +两个数字都在 [mid,r]内的

2、一个数字在[l,mid),一个数字在[mid,r]

3、若区间内只有2个数则只有第二种情况,第一种情况答案为0.

所以累加上每层的区间之间的逆序数即为整个序列的逆序数


而交换一下区间就是 2、中结果变成 : 一个数字在[mid,r] ,一个数字在[l,mid )

即每层的2有2种答案。

预处理出每层的2个答案,累加即可。

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <string>using namespace std;#define N 20#define ll __int64ll a[1 << N], n, m;//一个序列[l,r) 的翻转 = 将该序列的{[l,mid), [mid,r)} 交换 + ({[l,mid/2),[mid/2,mid)} + {[mid,mid+mid/2),[mid+mid/2,r)} ) + 如此递归下去ll sum[N + 1][2]; //sum[deep]表示 求和每段[l,r]的:[l,mid)和[mid,r) 之间的逆序数void dfs(ll l, ll r, ll deep){if(l+1 >= r)return ;ll mid = (l+r)/2;dfs(l, mid, deep-1);dfs(mid, r, deep-1);ll cnt = 0;for(ll i = l; i < mid; i++)cnt += lower_bound(a+mid, a+r, a[i]) - (a+mid);sum[deep][0] += cnt; cnt = 0;for(ll i = mid; i < r; i++)cnt += lower_bound(a+l, a+mid, a[i]) - (a+l);sum[deep][1] += cnt;inplace_merge(a+l, a+mid, a+r);}int main(){ll n, i, que, u;ll er[30];er[0] = 1;for(i=1;i<30;i++)er[i] = er[i-1]*2;while(~scanf("%I64d",&n)){memset(sum, 0, sizeof sum);for(i = 0; i < er[n]; i++)scanf("%I64d",&a[i]);dfs(0, er[n], n);scanf("%I64d",&que);while(que--){scanf("%I64d",&u);ll ans = 0;while(u--)swap(sum[u+1][0], sum[u+1][1]);for(i=0; i <= n; i++) ans += sum[i][0];printf("%I64d\n",ans);}}return 0;}





0 0
原创粉丝点击