池塘钓鱼
题目:http://ybt.ssoier.cn:8088/problem_show.php?pid=1373
好吧,在堆类型的题中我看到这道题第一个想到的居然是动态规划……
1、DP
状态转移方程:F[ i ][ j ] = max{ f[ i-1 ][ j - T[ i-1 ] - k ] } + fish[ i ][ k ] ; ---- by TPY
F[i][j] 表示的是:前i个池塘用j个单位的时间能够钓到的最多鱼的数量;k表示在第i个池塘停留k个单位的时间; T[ i ] 表示从第i个池塘到第i+1个池塘所需要的时间;
当然我并不是很想写,手很懒……
2、“堆”
Emmm,看了下面代码的大概知道为什么“堆”字有引号了吧,嘻嘻,懒,真的不想写手写堆,偷工减料用了优先队列。
不如先讲讲思路:
第一次见到这道题是1两2个月前了,抠脑壳,不知道怎么和堆建立联系。因为从某个鱼塘到相邻鱼塘之间还有时间啊,这个该如何考虑呢?
如果您在想 守望先锋 里的“秩序之光” 角色的话,那你基本上就能够解决这道题行走池塘之间的时间的问题了!
为什么呢?记得她的 Q 技能吗 —— 传送门!
我们可以枚举:第一个鱼塘到第i个池塘,然后计算在这区间 [1,i] 能够钓的最多的鱼!(因为数据范围不是很大)
鱼塘间的时间问题:刚刚提到了传送门,那么我们可以想象:我们在每个鱼塘间用相同的时间安装可以供我们 无时间间隔来回跳跃的传送门。之后没有了时间间隔,就很好解决了。由于区间 [1,i] 中一定有一个含有最大鱼 数量的鱼塘,于是将那个鱼塘从优先队列弹出,在减去它每被钓一次的衰减数量,再入队,成为一个新的池塘这就 完成了一次钓鱼!
某大佬(TPY)问,那万一你要往回走呢?你这个传送门不是要被使用多次吗,使用多次跳鱼塘的时间就不可 能只用减一次啊!
本蒟蒻:喔,不会的,如果你在钓完第i个鱼塘之后发现前面还有更加优秀的鱼塘,你根本不需要走回去。你 只需要在走到第i个池塘之前就先钓了这个池塘就是了,是不是?
某大佬:诶,对……但是你万一漏掉情况了呢?万一到第i个池塘之前就已经没有时间了呢?
本蒟蒻:Emmm,不会的,枚举嘛。如果到第i个池塘的途中已经把时间使用完了,那么这个情况的最优解一定 在之前就已经出现过了!
某大佬:That's ♂ Good! 所以ANS每次都会被更新的啊,懂了!
好了,思路就是这样。
看代码……
#include<bits/stdc++.h>
using namespace std;
const int N=10000+5;
struct node{
int id,fish;
bool operator < (const node &y)const{
return fish<y.fish;
}
node():fish(0),id(0){}
node(const int fish,const int id):
fish(fish),id(id){}
};
node a[N];
int n,t,ANS,MAX,T[N],discnt[N];
priority_queue< node > qx;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].fish;a[i].id=i;
}
for(int i=1;i<=n;i++)
cin>>discnt[i];
for(int i=1;i<=n-1;i++){
cin>>T[i];
T[i]+=T[i-1];
}
cin>>t;
for(int i=1;i<=n;i++){
while(!qx.empty()) qx.pop();
int tmptop=t;
tmptop-=T[i-1];
for(int j=1;j<=i;j++)
qx.push(node(a[j].fish,j));
while(tmptop>0){
node tmpx=qx.top();
qx.pop();
ANS+=tmpx.fish;
tmpx.fish-=discnt[tmpx.id];
if(tmpx.fish<0)
tmpx.fish=0;
qx.push(tmpx);
tmptop--;
}
MAX=max(ANS,MAX);
ANS=0;
}
cout<<MAX;
return 0;
}
啊咧,成都下了场不太认真的雪啊。还是4年前马里兰的雪大,都过膝头了。不过内心的雪应该是最大的了……
努力嘻嘻