2021 五星级挑战 消除交叉
相似题目:
一些结论
首先看到交换相邻的,很容易能够想到逆序对。
接着再来看每个点都有确定的想要去的地方,那肯定是逆序对了呀!
有一个一眼可以看出的结论。
就是我们可以只调换终点相邻的,起点不调换。
或者只调换起点相邻的,终点不管。
证明很简单,相对性。
还有一个结论,为了消除交叉,最后一定是这种样子:
证明也很简单,反证法。
我们现在假如知道了一个航线的起点,那么我们就可以推出它的终点,比如样例:
构造目标数组
我们用
输入起点的时候统计一个辅助数组
然后输入终点时,假如当前输入的是
how to do it?
如果我们让
于是乎,现在要干的事儿就是交换
所需要的最少步骤数就是该排列的逆序对数。
证明:在一个排列里交换两个相邻的元素,该排列的逆序对数量减一或加一。
逆序对有两个经典解法:树状数组,归并排序。
树状数组代码较为简洁,因为这题不需要离散化,所以我就贴一个树状数组的代码吧:
#include <iostream> using namespace std; long long n, x, ans; int a[100005], b[100005], l[100005]; long long c[100005]; void add (int x){for (; x <= n; x += x & -x) ++ c[x];} int query (int x){return x == 0 ? 0 : c[x] + query (x - (x & -x) );} int main() { ios::sync_with_stdio (false); cin >> n; for (int i = 1; i <= n; i ++) { cin >> x; a[x] = i; } for (int i = 1; i <= n; i ++) { cin >> x; l[i] = a[x]; } for (int i = n; i >= 1; i --) { add (l[i]); ans += query (l[i] - 1); } cout << ans << endl; return 0; }
分类:
YACS五星级挑战
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)