信息学奥赛一本通:1302:股票买卖 1305:Maximum sum

1302:股票买卖


【题目描述】

最近越来越多的人都投身股市,阿福也有点心动了。谨记着“股市有风险,入市需谨慎”,阿福决定先来研究一下简化版的股票买卖问题。

假设阿福已经准确预测出了某只股票在未来N天的价格,他希望买卖两次,使得获得的利润最高。为了计算简单起见,利润的计算方式为卖出的价格减去买入的价格。

同一天可以进行多次买卖。但是在第一次买入之后,必须要先卖出,然后才可以第二次买入。

现在,阿福想知道他最多可以获得多少利润。

【输入】

输入的第一行是一个整数T(T≤50),表示一共有T组数据。

接下来的每组数据,第一行是一个整数N(1≤N≤100,000),表示一共有N天。第二行是 N 个被空格分开的整数,表示每天该股票的价格。该股票每天的价格的绝对值均不会超过1,000,000。

【输出】

对于每组数据,输出一行。该行包含一个整数,表示阿福能够获得的最大的利润。

【输入样例】

3
7
5 14 -2 4 9 3 17
6
6 8 7 4 1 -2
4
18 9 5 2

【输出样例】

28
2
0

#include<bits/stdc++.h> 
using namespace std;
//因为当天的股票可买卖 有点像登山或是合唱队形 
//当前股票与前面最小值的差加上当前股票与后面最大值的差,取最大的那个 
int n,t,fl[100005],fh[100005],a[100005];
//fl是取从左最小值的到每天的利润 fh是取从右最大值时到每天的利润 
int main()
{
    int minx,maxy;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
        minx=a[1]; maxy=a[n];
        for(int i=1;i<=n;i++){//当前与前面最小值的利润 
            minx=min(minx,a[i]);
            fl[i]=max(fl[i-1],a[i]-minx);//取个前面的大值 
        }
        fh[n+1]=0;//因为不是一组数,防这个位有数 
        for(int i=n;i>=1;i--)//当前与后面最大值的利润 
        {
            maxy=max(maxy,a[i]);//取个后面的大值 
            fh[i]=max(fh[i+1],maxy-a[i]);
        }
        maxy=0;
        for(int i=1;i<=n;i++)//找到最大值 
        maxy=max(maxy,fl[i]+fh[i]);
        printf("%d\n",maxy);
    }
}

1305:Maximum sum

【题目描述】

对于给定的整数序列A={a1,a2,...,an},找出两个不重合连续子段,使得两子段中所有数字的和最大。1≤s1≤t1<s2≤t2≤n,就是求最大(s1到t1最大子段和s2到t2最大子段和相加)

【输入】

第一行是一个整数T(≤30),代表一共有多少组数据。

接下来是T组数据。

每组数据的第一行是一个整数,代表数据个数据n(2≤n≤50000) ,第二行是n个整数a1,a2,...,an(|ai|≤10000)。

【输出】

输出一个整数。

【输入样例】

1
10
1 -1 2 2 3 -3 4 -4 5 -5

【输出样例】

13

/*以i分数组,i前的最大子段和与i+1到n的最大子段和,找出最大和的值
从左到每位上的最大子段和,如前面求得的和大于0,可加在当前位上,否则只是当前位上的值
从右到每位上的最大子段和,如后面的子段和大于0,可加在当前位上,否则只是当前位上的值 */
#include<bits/stdc++.h>
using namespace std;
int fl[50005],fr[50005],n,t,a[50005];
//fl是从左开始的到每位的最大子段和 
//fr是从右开始到每位的最大子段和 
int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)// 
            scanf("%d",&a[i]);
    //从左到每个位的最大子段和 
        for(int i=1;i<=n;i++) 
              if(fl[i-1]<=0)    fl[i]=a[i]; 
              else      fl[i]=fl[i-1]+a[i];
    //从右到左到每位上的最大子段和 
        fr[n+1]=0;//以防这里有数    
        for(int i=n;i>1;i--) 
              if(fr[i+1]<=0)    fr[i]=a[i];//如果比0小,就不加上它了 
              else      fr[i]=fr[i+1]+a[i]; 
        int maxx=-0x3e3e3e3e;
        int maxy=maxx;
        for(int i=1;i<n;i++)//以i为分点 
        {
            maxx=max(maxx,fl[i]);//到每个位的最大子段和 
            maxy=max(maxy,maxx+fr[i+1]);//前后两个子段和 
        }
        cout<<maxy<<endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值