@xiaoziyao
2020-12-27T16:50:38.000000Z
字数 1275
阅读 1145
解题报告
CF713C Sonya and Problem Wihtout a Legend解题报告:
四倍经验:(前三题为使得序列非严格递增)
P4597 序列sequence
CF13C Sequence
P2893 [USACO08FEB]Making the Grade G
CF713C Sonya and Problem Wihtout a Legend
首先有一个套路的想法,将减去,这样可以使得求严格递增改为非严格递增,因为我们需要考虑的只是之间的相对大小关系,因此把减去并求非严格递增序列之后,我们加回这个,就可以让相邻两项之间差增加一,变为严格递增。
转化之后,我们考虑如何求解。
考虑下面一种想法(主要是我想不到怎么正向考虑这种诡异的想法,只能强行说明这个做法的正确性):
我们边维护序列边用优先队列维护当前修改过的序列的最大值,每当我们得到一个数,我们先把它加入优先队列,然后取出堆顶(如果有多个最大值,我们取出靠后的),如果,我们不用管,如果,我们强行把修改为(即掉堆顶,并新进一个)。
我们考虑任意一种调整方法,发现对于逆序对,我们发现是不可能减小的(否则就更不优了),而我们的算法先钦定了不减小,所以算法在以后的选择一定会更优,因此我们发现这个代价达到了下界。
然后考虑一个问题:如果修改为之后,前面的最大值大于了(即),那么这种构造的代价是否不合法?
我们构造到最后,这个有可能也被修改了,我们不妨讨论最终的值。
我们定义“微调”为不改变花费的情况下,改变某个数对的值。
如果,那么我们可以强行把和强行微调成(考虑正确性:因为,所以在进行和的强行修改时可以用一种反悔的思想将和同时改成,此时花费仍然为),这样和的矛盾就不存在了。
如果,那么我们发现它与和不再存在矛盾,而它之前的数与它的矛盾可以用类似归纳法一样的方式证明微调可以使得花费不变。
时间复杂度:。
#include<stdio.h>
#include<queue>
using namespace std;
int n;
long long ans;
priority_queue<int>q;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
x-=i,q.push(x);
if(x<q.top()){
ans+=q.top()-x;
q.pop(),q.push(x);
}
}
printf("%lld\n",ans);
return 0;
}