(前缀和) “达梦杯”武汉理工大学第五届新生程序设计大赛 D题

先上题面:

题目描述

演员Jakon喜欢在群里呼风唤雨。
从而召唤出一阵阵的风和雨,导致每次Eriktse不得不在群里打伞。

众所周知,先有风后有雨。
现在空中有N股神秘力量,它们要么是“风”,要么是“雨”,且“雨”一定在“风”的后面,且不会出现“只有风”或“只有雨”的情况。
换句话说,若把神秘力量从1到N编号,则存在一个分界点K使得[1,K]全是风,[K+1,N]全是雨。(1≤K<N)
每一股神秘力量有一个初始能量ai ,如果将这份力量看作“风”,则这一股的真实能量为ai×114,如果看作“雨”,则这一股真实能量为ai×514。
Eriktse的伞的1点防护值可以挡住1的能量。
能量和为所有神秘力量的真实能量之和,求Eriktse的伞至少需要多少防护值F(F≥0)才能抵挡住Jakon的风雨。

输入描述:

有多组测试样例。

第一行一个整数T,表示测试样例数量(1≤T≤10)。

一个整数N,表示神秘力量的股数(2≤N≤10^6)。

接下来N个整数,表示第i股神秘力量的初始能量ai (−10^10≤ai≤10^10)

输出描述:

对于每一个测试用例,输出一个整数表示Eriktse的伞需要的最小防护值F(F≥0)

输入

2
5
2 -9 3 7 5
6
3 3 -5 99 8 7

输出

6912
58710

 解题思路:

因为是 无法确定的分割点,并且题目限制有所限制,风和雨最小个数都是1,所以我们可以尝试,将分割点放在第一个元素后、第二个元素后、第三个元素后......直到最后一个元素之前,以第一个示例为例

思路是好的,但要看题目给的数据范围。

我们可以考虑用前缀和进行处理。

代码实现: 

 int型变量显然是无法存储10^10这样的数据,我们考虑用long long来处理;

全部代码如下:

#include <iostream>
typedef long long ll;
using namespace std;
int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        ll t;
        cin>>t;
        ll b[t+1],c[t+1];
        b[0]=0;
        
        for(int i=1;i<t+1;i++)
        {
            scanf("%lld",&b[i]);
            b[i]+=b[i-1];
        }
        //前缀和求和。

        ll max=0;
        for(int i=1;i<t+1;i++)
        {
            c[i]=b[i]*114+(b[t]-b[i])*514;
            if(max<c[i])
                max=c[i];
        }
        //找出最大值
        cout<<max<<endl;
    }
    return 0;
}

来分别理解一下求和部分和找出最大值的部分。

1.求值部分,以第一个样例为例:

for(int i=1;i<t+1;i++)
        {
            scanf("%lld",&b[i]);
            b[i]+=b[i-1];
        }

b[1]=2;   b[2]=2+(-9)=7;    b[3]=2+(-9)+3=-4;

b[3]-b[1]=-6;   b[3]-b[2]=3;

由此可见,b[n]就是前n项的和。我们也就可以用数组内部元素相减来部分项的和。

2.找出最大值,仍以第一个样例为例

 ll max=0;
        for(int i=1;i<t+1;i++)
        {
            c[i]=b[i]*114+(b[t]-b[i])*514;
            if(max<c[i])
                max=c[i];
        }

我们用上面的思路图来理解:

c[1]=2*114+(-9+3+7+5)*514

c[2]=(2-9)*114+(3+7+5)*514

……

以此来进行求和,然后利用循环比较来寻找最大。

最后输出这个max内所存的值。

 2022/11/24 11:00

个人愚见,若有更好思路或解法,亦或文中出现错误,欢迎提出您的看法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值