标签:getc code 最大 5* ext lis otto 自己 std
【题目背景:】
原题cf13c 数据加强版(就是说原来能用DP做现在不行了QwQ)
【题目描述:】
给定一个序列,每次操作可以把某个数+1-1。要求把序列变成非降数列。而且要求修改后的数列只能出现修改前的数。
【输入格式:】
第一行输入一个n,表示有n( n \leq 5*10^5n≤5?105 )个数字。第二行输入n个整数,整数的绝对值不超过 10^9109
【输出格式:】
输出一个数,表示最少的操作次数
【算法分析:】
切题背景:
chen_zhe大佬改编了这道题目之后吸引了slyz准高一全机房同学的注意
主要是一开始是道紫题想要通过以后强行把它变黑(雾
然后全机房的同学刚了一节课4597无果(中间它突然变成了黑题QwQ)
然后就被隔壁机房的学长学姐拯救了...
自己想的证明:
对于一个序列,可以看成高度不同的几根线
如:序列{3、 4、 1、 5}可以看做这样
---- ---- ---- ----
对于一个大数a和一个小数b,要做的就是在他们之间的任意位置找到一个基准,将大数向下挪到那个基准,小数向上挪到那个基准
移动的距离等价于a - b
由于是非降序列,将a向下移动的距离越多越可以使之后的数字更容易变成非降序列
所以这个基准应该是选择之前的最小数c,而之前的最小数一定是在[a, b]这个区间内,将a向下移到c并将b向上移到c的距离等价于将a向下移动到b的距离
所以就把a移到b就好了
然后开个大根堆瞎搞:
对于读进的一个数num,把它push到优先队列里去
如果这个num比之前的最大值maxn(就是堆顶元素)要小的话
ans += maxn - num
并把maxn弹出,再push进一个num(把maxn移动到了num的位置)
【代码:】
1 //序列sequence加强版 2 #include<iostream> 3 #include<cstdio> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 8 int n; 9 long long ans; 10 priority_queue<int> q; 11 12 inline int read() { 13 int x = 0, f = 1; char ch = getchar(); 14 while(ch < ‘0‘ || ch > ‘9‘) { if(ch == ‘-‘) f = -1; ch = getchar(); } 15 while(ch >= ‘0‘ && ch <= ‘9‘) 16 x = (x << 3) + (x << 1) + ch - 48, ch = getchar(); 17 return x * f; 18 } 19 20 int main() { 21 n = read(); 22 for(int i = 1; i <= n; i++) { 23 int num = read(); 24 q.push(num); 25 if(num < q.top()) { 26 ans += q.top() - num; 27 q.pop(); 28 q.push(num); 29 } 30 } 31 printf("%lld\n", ans); 32 }
标签:getc code 最大 5* ext lis otto 自己 std
原文地址:https://www.cnblogs.com/devilk-sjj/p/9038078.html