转化思维的好题!

链接:here

大致题意:

有$ n$个数字,你每次可以交换相邻两个,还有一次交换任意两个元素的机会,求最少的交换次数使得这些数字升序排序(原数列两两不同)


$ solotion:$

首先有一个结论:交换任意两个元素可以选择在第一次交换,且一定不会劣

证明:假设不在第一次交换,可以通过倒推这次交换的贡献,使得这次机会平移到第一次交换,结果不变

第二个结论:交换相邻两个元素的次数等于逆序对数

证明:略

第三个结论:交换两个元素$ x,y$,所能够减少的逆序对数量等价于把每个数$ a_i$对应到坐标$ (i,a_i)$之后矩形{$(x,a_x),(y,a_y)$}中的点数$ *2+1$(不包含边界)

证明:在矩形内的每个点,原先会贡献$ 2$的逆序对,交换后将不再产生这样的贡献。$ +1$是因为交换本身会减少一个逆序对

也就是说我们实际要求的等价于找到一个矩形(两个角都在点上),使得矩形内点尽量多

这并不容易直接处理,考虑转化题意


选择的矩形两个角$(x,a_x),(y,a_y)$有性质如下:$(x<y)$

$ 1.a_x>a_y$ 证明:否则会增加逆序对数量,肯定不优

$ 2.a_x$是前缀最大值,$ a_y$是后缀最小值

证明:如果$ a_x$不是前缀最大值,一定有一个点$ (k,a_k)$在$ (x,a_x)$的左上方,这样的矩形能够完全包含矩形{$(x,a_x),(y,a_y)$}使得$ (x,a_x)$不可能成为最优,后缀最小值同理。

这样我们获得了一个前缀最大值数组$ S$,一个后缀最小值数组$ T$,我们对于每个点,计算哪些矩形能够包含这个点

显然包含这个点的矩形左端点要在这个点的左上方,右端点在这个点的右下方,可以通过两次二分得到包含这个点的两段数组区间

我们用$ (x,y)$表示左端点是前缀最大值第$ x$个,右端点是后缀最小值第$ y$个的矩形,可以发现能包含这个点的矩形用坐标表示后也是一个矩形

然后就把题意转化成有若干个矩形,求一个被最多矩形覆盖的位置 扫描线+线段树维护即可

时间复杂度:$ O(n log n)$

code:

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define file(x)freopen(x".in","r",stdin);freopen(x".out","w",stdout)
#define rt register int
#define ll long long
using namespace std;
inline ll read(){ll x = 0; char zf = 1; char ch = getchar();while (ch != '-' && !isdigit(ch)) ch = getchar();if (ch == '-') zf = -1, ch = getchar();while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}
void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);}
void writeln(const ll y){write(y);putchar('\n');}
int i,j,k,m,n,x,y,z,cnt;
int a[300010],c[300010];
void up(int x){for(rt i=x;i<=n;i+=i&-i)c[i]++;
}
int query(int x){int ans=0;for(rt i=x;i;i&=i-1)ans+=c[i];return ans;
}
int sta[300010],top;
int L1[300010],R1[300010],L2[300010],R2[300010];
struct query{int id,x,L,R;bool operator <(const query s)const{if(x==s.x)return id<s.id;return x<s.x;}
}q[600010];
struct segment{int L,R,Max,tag;
}t[300010*4];
void build(int x,int L,int R){t[x].L=L;t[x].R=R;if(L==R)return;const int mid=L+R>>1;build(x<<1,L,mid);build(x<<1|1,mid+1,R);
}
void change(int x,int L,int R,int val){if(t[x].L>=L&&t[x].R<=R){t[x].tag+=val;t[x].Max+=val;return;}const int mid=t[x].L+t[x].R>>1;if(mid>=L)change(x<<1,L,R,val);if(mid+1<=R)change(x<<1|1,L,R,val);t[x].Max=max(t[x<<1].Max,t[x<<1|1].Max)+t[x].tag;
}
int main(){n=read();ll ret=(ll)n*(n-1)/2;for(rt i=1;i<=n;i++)a[i]=read();for(rt i=1;i<=n;i++){ret-=query(a[i]-1);up(a[i]);}//ret计算初始逆序对数量 for(rt i=1;i<=n;i++){if(a[i]>sta[top]||!top)sta[++top]=a[i];    int pla=lower_bound(sta+1,sta+top+1,a[i])-sta;L1[i]=pla;L2[i]=top;}top=0;memset(sta,0,sizeof(sta));for(rt i=n;i>=1;i--){if(-a[i]>sta[top]||!top)sta[++top]=-a[i];int pla=lower_bound(sta+1,sta+top+1,-a[i])-sta;R1[i]=pla;R2[i]=top;}//L1 L2 R1 R2表示包含第i个点的合法矩形的范围 for(rt i=1;i<=n;i++){q[2*i-1]={1,L1[i],R1[i],R2[i]};q[2*i]={-1,L2[i]+1,R1[i],R2[i]};}sort(q+1,q+2*n+1);int ttt=2;build(1,1,top);for(rt i=1;i<=2*n;i++){change(1,q[i].L,q[i].R,q[i].id);ttt=max(ttt,t[1].Max);}cout<<ret-(ttt-2)*2;return 0;
}

转载于:https://www.cnblogs.com/DreamlessDreams/p/9846105.html

「LibreOJ Round #6」花火相关推荐

  1. loj #535. 「LibreOJ Round #6」花火 树状数组求逆序对+主席树二维数点+整体二分...

    $ \color{#0066ff}{ 题目描述 }$ 「Hanabi, hanabi--」 一听说祭典上没有烟火,Karen 一脸沮丧. 「有的哦-- 虽然比不上大型烟花就是了.」 还好 Shinob ...

  2. 「LibreOJ Round #11」Misaka Network 与求和(杜教筛 + Min_25)

    #572. 「LibreOJ Round #11」Misaka Network 与求和 推式子 ∑i=1n∑j=1nf(gcd(i,j))k∑d=1nf(d)k∑i=1nd∑j=1nd[gcd(i,j ...

  3. #530. 「LibreOJ β Round #5」最小倍数 二分 + 数论

    传送门 文章目录 题意: 思路: 题意: 思路: 本来想刷数位dpdpdp,无意间碰到了这个题来水水. 我们知道n!n!n!中质因子ppp的个数为∑i=1npi\sum_{i=1} \frac{n}{ ...

  4. [LOJ #521]「LibreOJ β Round #3」绯色 IOI(抵达)(结论)

    #521. 「LibreOJ β Round #3」绯色 IOI(抵达) description solution 因为点的庇护所不能为自身,题目背景在树上,有结论一定是两个相邻点互为庇护所 所以树一 ...

  5. LibreOJ545. 「LibreOJ β Round #7」小埋与游乐场【网络流】

    545. 「LibreOJ β Round #7」小埋与游乐场 [题目描述] 传送门 [题解] 网络流,我们发现lowbit之后相同的点连出的边是相同的,所以可以缩点. [代码如下] #include ...

  6. [LOJ#522]「LibreOJ β Round #3」绯色 IOI(危机)

    [LOJ#522]「LibreOJ β Round #3」绯色 IOI(危机) 试题描述 IOI 的比赛开始了.Jsp 和 Rlc 坐在一个角落,这时他们听到了一个异样的声音 -- 接着他们发现自己收 ...

  7. 「LibreOJ β Round #2」计算几何瞎暴力

    https://loj.ac/problem/517 题解 首先我们如果没有排序这个骚操作的话,可以直接记一下各个数位的前缀和,然后异或标记给全局打,查询的时候先把区间信息提取出来然后整体异或就好了. ...

  8. 「LibreOJ β Round #4」子集

    https://loj.ac/problem/526 题目描述 qmqmqm有一个长为 n 的数列 a1,a2,--,an,你需要选择集合{1,2,--,n}的一个子集,使得这个子集中任意两个元素 i ...

  9. LOJ #516. 「LibreOJ β Round #2」DP 一般看规律

    题目描述 给定一个长度为 n 的序列 a,一共有 m 个操作. 每次操作的内容为:给定 x,y,序列中所有 x 会变成 y. 同时我们有一份代码: int ans = 2147483647; for ...

最新文章

  1. OC之NSArray/NSMutableArrray
  2. Spring MVC 成员变量 request 线程安全问题的讨论
  3. jquery mobile用代码弹出dialog
  4. HTML5中拖动功能的添加属性,html5中可拖动dragable属性及其他成员的讲解
  5. node下使用jquery
  6. 苹果无人车裁员200人,收购特斯拉呼声再起
  7. C#各种文件操作的代码与注释
  8. Linux内核移植操作步骤
  9. 《JAVA疯狂讲义》学习笔记第六天
  10. 计算机语言缩写 dos,dos是什么意思 dos缩写中英全称是什么
  11. MATLAB绘图—三维网格绘图(mesh)
  12. 什么是SVC?AVC和SVC有什么区别
  13. Servlet的Request和Response
  14. Incapsula js加密混淆分析
  15. 《AngularJS深度剖析与最佳实践》一1.3 创建项目
  16. SpringBoot入门系列(二)如何返回统一的Json数据格式
  17. 蓝鲸CMP:跳出云管看云管
  18. JPG和TIFF图像转换
  19. matlab+字体设置大小,Matlab中如何修改字体的大小?
  20. html做秒表代码,利用JS实现一个可精确到10ms的秒表的制作(附代码)

热门文章

  1. xhtml使用style属性
  2. python博弈论代码_使用 40 多行的 Python 代码实现一个简单的演化过程
  3. 嵌入式Linux基础学习笔记-文件IO编程-文件锁(1)
  4. [BUUCTF-pwn]——picoctf_2018_buffer overflow 2
  5. cvs update 的输出标志/update常用几个参
  6. Index of c#
  7. loj10165. 「一本通 5.3 例 3」Windy 数
  8. Gmail技巧之无限别名
  9. 115开jiang监控
  10. Hadoop的数据管理