誰能拿到最多的硬幣

描述
有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; 
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章