题解 AT1757 【花火】
弃了好久的题,时隔良久又翻出来,终于像是有了思路
我们贪心的想
如果没有不能向后走的限制的话
我们每次都到烟花的释放点,有多个释放点就取中间点
这是非常好想的
但是如果加上这个限制呢?
局部贪心就不是最优解了
考虑不加限制时的过程,当ニワンゴくん向后走时,
如果这并不是实际最优解,即ニワンゴくん当前这步走的比最优解多
我们就将这步拉回来,并重新计算贡献
具体怎么实现呢?代码可能写的有点奇怪
就拿样例说吧,
5 10
1 2
1 4
3 8
4 7
5 1
我们按时间倒着排序,来避免对后面造成的影响
首先,站在原点不动的代价是
第一个是
当前在零位置,到
第二个是
当前在
第三个是
当前在
第四个是
当前在
第五个是
因为时间与第四个是一致的,代价一定是
总代价为
思考我们的过程,回到之前的不需要代价,向后需要的代价为其坐标的绝对值
所以可以直接把当前的
这里之所以压入两次是为了去掉之前
#include<iostream>
#include<cstdio>
#include<ctype.h>
#include<set>
#include<queue>
#define int long long
using namespace std;
inline int read(){
int x=0,f=0;char ch=getchar();
while(!isdigit(ch))f|=ch=='-',ch=getchar();
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
return f?-x:x;
}
typedef pair<int,int> pairs;
priority_queue<int> q;
multiset<pairs> v;
signed main(){
int n=read(),sum=0,ans=0;read();
while(n--){
int t=read(),p=read();
v.insert(make_pair(-t,p));
sum+=p;
}
for(multiset<pairs>::iterator it=v.begin();it!=v.end();it++){
q.push(-(*it).second),q.push(-(*it).second);
ans+=q.top(),q.pop();
}
printf("%lld\n",ans+sum);
return 0;
}