题解:ARC22E题题解

· · 题解

:::warning[闲话] orz 小清新思维压轴题。 :::

:::info[题目信息] 算法:排序,构造

kenkooo难度:2645

通过人数:75 / 1552 :::

:::success[Hint1] 本题代码二十二行。 :::

:::success[Hint2] 对比这道题与上一道题的代价的区别,总结一下这道题代价与上一道题代价之间的等量关系。 :::

:::success[Hint3] 我们容易求出如果每次交换相邻两个数,最小的交换次数。 :::

:::success[Hint4] Hint3 中所说的次数等于逆序对数量。 :::

:::success[Hint5] 瞪出 分析逆序对数量,D 题答案,E 题答案的关系。 :::

:::success[题解(Hard)] 注意到,如果我们每次交换相邻的两个数,代价为 2i-2j-1

设 $f(p)$ 为逆序对数量,$d(p)$ 为 D 题答案,$e(p)$ 为 E 题答案。 列出等式 $2d(p)-e(p)=f(p)$。 移项得 $e(p)=2d(p)-f(p)$。 使用树状数组计算 $f(p)$,使用上一题的代码计算 $d(p)$,输出 $2d(p)-f(p)$ 即可。 感性理解一下,我们的 D 题是一个最小化策略,而逆序对也是一个最小化的策略,如果将任意一个变大,第二个的变小量都不超过这个的变大量,所以拼出的也是一个最小化的策略。 具体细节留给各位巨佬去证明吧,本蒟蒻太菜了,不会,如果大家想出了证明,欢迎评论。 ::: :::info[代码(Hard)] ```cpp #include <bits/stdc++.h> using namespace std; #define int long long int a[500010],sum,sum2; int c[500010]; void insert(int id){ while (id<=500000) c[id]++,id+=(id&(-id)); } int query(int id){ int ans=0; while (id) ans+=c[id],id-=(id&(-id)); return ans; } signed main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n; cin>>n; for (int i=1; i<=n; i++){ int x; cin>>x; sum+=abs(x-i); sum2+=i-1-query(x); insert(x); } cout<<sum-sum2<<"\n"; } ``` ::: :::error[常见错误] 不要忘记开 long long。 :::