信息学奥赛一本通 1373池塘钓鱼

池塘钓鱼

题目: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
using namespace std;
const int N=10000+5;
struct node{
	int id,fish;
	
	bool operator < (const node &y)const{
		return fish 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<
啊咧,成都下了场不太认真的雪啊。还是4年前马里兰的雪大,都过膝头了。不过内心的雪应该是最大的了……

努力嘻嘻

你可能感兴趣的:(堆,queue)