题解 [CF713C] Sonya and Problem Wihtout a Legend
CF713C Sonya and Problem Wihtout a Legend
CF13C Sequence
首先先有一个结论:最后的序列中的每个数字肯定是在原先的序列中出现过的数字
证明可以归纳证明,见蓝书P268
先将a数组排序后的结果存在一个b数组中
然后考虑DP,令 \(dp[i][j]\) 为考虑到第 \(i\) 个位置,将这个位置上的值调整为 \(b_j\) 的最小花费
转移的话
\[dp[i][j]=\min\limits_{0\leqslant k \leqslant j}\{dp[i-1][k]+|a_i-b_j|\}
\]
这个DP是 \(O(n^3)\)的,如何优化呢?
发现可行的决策集合是单调增加的,也就是随着 \(k\) 增加,可行的决策值单调不降
什么意思呢?换个写法可能就显然多了
\[dp[i][j]=\min\limits_{0\leqslant k \leqslant j}\{dp[i-1][k]\}+|a_i-b_j|
\]
于是记录一下前缀最小值即可 \(O(1)\) 转移了
然后加强版:
先扔几个链接和链接
先有一个技巧可以将单调递增弱化为单调不降,方法是将 \(a_i\) 变为 \(a_i-i\)
这样大概是在保证其相对大小?
然后可以slope trick处理
令 \(f_i(x)\) 为第 \(i\) 个数 \(\leqslant x\) 的最小花费
令 \(g_i(x)\) 为第 \(i\) 个数 \(=x\) 的最小花费
于是 \(g_i(x)=f_{i-1}(x)+|a_i-x|\)
这两个都是凸函数,于是 \(g\) 也是凸函数
f其实是g的前缀最小值
然后剩下的第个链接里的第三篇题解写的很详细
关于最终的统计答案:发现若合并一个 \(g\) 和绝对值时,多重集内已经存在一个比绝对值的拐点更靠右的点了
那么发现这个最小值将在 \(x\) 以右取到
所以对 \(f\) 的常数项的贡献是差值的绝对值
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 500010
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n;
ll a[N], ans;
priority_queue<ll> q;
signed main()
{
n=read();
for (int i=1; i<=n; ++i) a[i]=read();
for (int i=1; i<=n; ++i) {
q.push(a[i]);
if (q.top()>a[i]) {
ans+=q.top()-a[i];
q.pop();
q.push(a[i]);
}
}
printf("%lld\n", ans);
return 0;
}