「LibreOJ Round #6」花火
转化思维的好题!
链接: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」花火相关推荐
- loj #535. 「LibreOJ Round #6」花火 树状数组求逆序对+主席树二维数点+整体二分...
$ \color{#0066ff}{ 题目描述 }$ 「Hanabi, hanabi--」 一听说祭典上没有烟火,Karen 一脸沮丧. 「有的哦-- 虽然比不上大型烟花就是了.」 还好 Shinob ...
- 「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 ...
- #530. 「LibreOJ β Round #5」最小倍数 二分 + 数论
传送门 文章目录 题意: 思路: 题意: 思路: 本来想刷数位dpdpdp,无意间碰到了这个题来水水. 我们知道n!n!n!中质因子ppp的个数为∑i=1npi\sum_{i=1} \frac{n}{ ...
- [LOJ #521]「LibreOJ β Round #3」绯色 IOI(抵达)(结论)
#521. 「LibreOJ β Round #3」绯色 IOI(抵达) description solution 因为点的庇护所不能为自身,题目背景在树上,有结论一定是两个相邻点互为庇护所 所以树一 ...
- LibreOJ545. 「LibreOJ β Round #7」小埋与游乐场【网络流】
545. 「LibreOJ β Round #7」小埋与游乐场 [题目描述] 传送门 [题解] 网络流,我们发现lowbit之后相同的点连出的边是相同的,所以可以缩点. [代码如下] #include ...
- [LOJ#522]「LibreOJ β Round #3」绯色 IOI(危机)
[LOJ#522]「LibreOJ β Round #3」绯色 IOI(危机) 试题描述 IOI 的比赛开始了.Jsp 和 Rlc 坐在一个角落,这时他们听到了一个异样的声音 -- 接着他们发现自己收 ...
- 「LibreOJ β Round #2」计算几何瞎暴力
https://loj.ac/problem/517 题解 首先我们如果没有排序这个骚操作的话,可以直接记一下各个数位的前缀和,然后异或标记给全局打,查询的时候先把区间信息提取出来然后整体异或就好了. ...
- 「LibreOJ β Round #4」子集
https://loj.ac/problem/526 题目描述 qmqmqm有一个长为 n 的数列 a1,a2,--,an,你需要选择集合{1,2,--,n}的一个子集,使得这个子集中任意两个元素 i ...
- LOJ #516. 「LibreOJ β Round #2」DP 一般看规律
题目描述 给定一个长度为 n 的序列 a,一共有 m 个操作. 每次操作的内容为:给定 x,y,序列中所有 x 会变成 y. 同时我们有一份代码: int ans = 2147483647; for ...
最新文章
- OC之NSArray/NSMutableArrray
- Spring MVC 成员变量 request 线程安全问题的讨论
- jquery mobile用代码弹出dialog
- HTML5中拖动功能的添加属性,html5中可拖动dragable属性及其他成员的讲解
- node下使用jquery
- 苹果无人车裁员200人,收购特斯拉呼声再起
- C#各种文件操作的代码与注释
- Linux内核移植操作步骤
- 《JAVA疯狂讲义》学习笔记第六天
- 计算机语言缩写 dos,dos是什么意思 dos缩写中英全称是什么
- MATLAB绘图—三维网格绘图(mesh)
- 什么是SVC?AVC和SVC有什么区别
- Servlet的Request和Response
- Incapsula js加密混淆分析
- 《AngularJS深度剖析与最佳实践》一1.3 创建项目
- SpringBoot入门系列(二)如何返回统一的Json数据格式
- 蓝鲸CMP:跳出云管看云管
- JPG和TIFF图像转换
- matlab+字体设置大小,Matlab中如何修改字体的大小?
- html做秒表代码,利用JS实现一个可精确到10ms的秒表的制作(附代码)