谁能拿到最多的硬币

描述
有n个硬币排成一排,每个硬币上用一个数字标识了它的价值。每次要你从最左边或者最右边拿出一个硬币。总共拿k次,写一个算法,使能拿到的硬币的价值和最大。

关于输入
输入包含两行,第一行为n, k;
第二行包含n个数字,表示n个硬币的价值。

1 <= k <= n <= 100000
单个硬币的价值大于0且不超过10000.

关于输出
输出可以拿到的k个硬币最大的价值和。

例子输入

6 3

5 4 3 2 1 6

例子输出

15


由于只能连续地取左边几个和右边几个,所以答案是对 [0 , k] 之间的 i ,前面 i 个数和后面 k-i 个数的和的最大值。用aia_i表示第 i 个数,于是有这个方程:
ans=max0ik,iZ(j=0iaj+j=n(ki)+1naj) ans=\max_{0\leqslant i\leqslant k \,,\, i\in\mathbb Z}\Biggl( \sum_{j=0}^i a_j +\sum_{j=n-(k-i)+1}^n a_j\Biggr) 但是,如果对于每个 i 都算一下两个求和,肯定会超时(根据许多人的经验)
这里我们用前缀和优化一下,省略掉求和的过程(CSDN上可以搜到详细解说)
用ps[i]表示前i个数的和
所以第i个数到第j个数的和等于ps[j]-ps[i-1]
这样,上面的式子可以换成:
ans=max0ik,iZ(psi+psnpsn(ki)) ans=\max_{0\leqslant i\leqslant k \,,\, i\in\mathbb Z}\bigl( ps_i +ps_n-ps_{n-(k-i)}\bigr) 让 i 走一遍循环,即可得出结果。


废话不说,上代码

C++

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int ps[100005];
int main(){
	int n,k,ma=0;
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%d",&ps[i]);
		ps[i]+=ps[i-1];//求出前缀和
	} 
	for(int i=0;i<=k;i++)
		ma=max(ma,ps[i]+ps[n]-ps[n-(k-i)]);
	printf("%d",ma);
	
	return 0; 
} 

C

#include<stdio.h>
#include<string.h>
int ps[100005];
int main(){
	int n,k,i,ma=0;
	scanf("%d%d",&n,&k);
	for(i=1;i<=n;i++){
		scanf("%d",&ps[i]);
		ps[i]+=ps[i-1];//求出前缀和
	} 
	for(i=0;i<=k;i++)
		if(ma<ps[i]+ps[n]-ps[n-(k-i)])
			ma=ps[i]+ps[n]-ps[n-(k-i)];
	printf("%d",ma);
	
	return 0; 
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章