• [CSP-S模拟测试]:trade(反悔贪心)


    题目传送门(内部题62)


    输入格式

    第一行有一个整数$n$。
    第二行有$N$个整数:$a_1 a_2 a_3cdotcdotcdot a_n$。


    输出格式

    一行一个整数表示最大收益。


    样例

    样例输入:

    5
    1 1 5 3 6

    样例输出:

    9


    数据范围与提示

    样例解释:

    第$1,2$天分别买入一件货物,第$3,5$天分别卖出一件货物,第$4$天不进行交易。

    $-1-1+5+6=9$。

    数据范围:

    对于所有数据,$nleqslant 10^5$,$0leqslant a_ileqslant 10^6$。


    题解

    一个很显然的问题,最后一定是要把所有买的物品卖光。

    那么,我们先来考虑$DP$,设$dp[i][j]$表示到了第$i$天,手里有$j$个物品的最大收益即可。

    则转移方程为:

    $$dp[i][j]=max(dp[i-1][j],dp[i-1][j-1]-a[i],dp[i-1][j+1]+a[i])$$

    在来考虑一下$j$上界的问题,因为我们到了第$i$天最多会有$i$件物品,最后还要卖光,所以$j$的区间其实是如下图中红色区域:

    考虑这样一个有关考试策略的问题,我们可以将其上界设为$1000$左右,这样对于$70\%$的数据,上界最多会是$500$,然而对于$100\%$的数据我们还有可能过掉,何乐而不为?

    用滚动数组即可,还不用清空。

    其实上界设成$471$就可以$AC$啦~

    现在来考虑正解,当时我以为是线段树优化$DP$,因为那个式子简直太像了!!!

    然而这却是一道反悔贪心……

    考虑新的一天如果有单价为$b$的货物,之前有单价为$a(a<b)$的货物,那么我们的策略一定是卖$b$买$a$,即$b-a$。
    显然,买$a$这个决策在现在和以后一定是最优的,但是$a$与$b$配对并不一定是最优的,以后可能会出现$c(c>b)$,$c−a$才是最优策略。这时,我们就采用可反悔的贪心策略,用小跟堆维护即可。

    时间复杂度:$Theta(nlog n)$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    $DP$:

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    long long dp[2][100001];
    long long ans;
    bool now;
    int main()
    {
    	scanf("%d",&n);
    	memset(dp,-0x3f,sizeof(dp));
    	dp[0][0]=0;
    	for(int i=1;i<=n;i++)
    	{
    		int a,minn=min(471,min(i,n-i));
    		scanf("%d",&a);now^=1;
    		for(int j=0;j<=minn;j++)
    		{
    			dp[now][j]=dp[!now][j];
    			dp[now][j]=max(dp[now][j],dp[!now][j-1]-a);
    			dp[now][j]=max(dp[now][j],dp[!now][j+1]+a);
    		}
    	}
    	printf("%lld",dp[now][0]);
    	return 0;
    }
    

    反悔贪心:

    #include<bits/stdc++.h>
    using namespace std;
    int n,a;
    priority_queue<int,vector<int>,greater<int> > q;
    long long ans;
    int main()
    {
    	scanf("%d%d",&n,&a);
    	q.push(a);ans=-a;
    	for(int i=2;i<=n;i++)
    	{
    		scanf("%d",&a);
    		q.push(a);
    		ans-=a;
    		if(q.top()<a)
    		{
    			q.push(a);
    			q.pop();
    		}
    	}
    	while(q.size())
    	{
    		ans+=q.top();
    		q.pop();
    	}
    	printf("%lld",ans);
    	return 0;
    }

    rp++

  • 相关阅读:
    ubuntu安装php的 mongodb扩展
    ubuntu安装php的 redis扩展
    Ubuntu14.04下安装Composer
    编译安装php
    RabbitMQ PHP扩展安装
    编译安装opssl
    安装卸载nginx
    本地VM安装虚拟机,使用xshell连接
    下载并破解IntelliJ IDEA(2017)
    symfony框架中使用service
  • 原文地址:https://www.cnblogs.com/wzc521/p/11636314.html
Copyright © 2020-2023  润新知