先上题面:
题目描述
演员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
个人愚见,若有更好思路或解法,亦或文中出现错误,欢迎提出您的看法