問題 A: 最大連續子序列
時間限制: 1 Sec 內存限制: 32 MB
提交: 380 解決: 170
[提交][狀態][討論版][命題人:外部導入]
題目描述
給定K個整數的序列{ N1, N2, ..., NK },其任意連續子序列可表示爲{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j <= K。最大連續子序列是所有連續子序列中元素和最大的一個,例如給定序列{ -2, 11, -4, 13, -5, -2 },其最大連續子序列爲{ 11, -4, 13 },最大和爲20。現在增加一個要求,即還需要輸出該子序列的第一個和最後一個元素。
輸入
測試輸入包含若干測試用例,每個測試用例佔2行,第1行給出正整數K( K<= 10000 ),第2行給出K個整數,中間用空格分隔,每個數的絕對值不超過100。當K爲0時,輸入結束,該用例不被處理。
輸出
對每個測試用例,在1行裏輸出最大和、最大連續子序列的第一個和最後一個元素,中間用空格分隔。如果最大連續子序列不唯一,則輸出序號i和j最小的那個(如輸入樣例的第2、3組)。若所有K個元素都是負數,則定義其最大和爲0,輸出整個序列的首尾元素。
樣例輸入
5 -3 9 -2 5 -4 3 -2 -3 -1 0
樣例輸出
12 9 5 0 -2 -1
提示
這是一道稍微有點難度的動態規劃題。
首先可以想到的做法是枚舉每個區間的和,預處理sum[i]來表示區間[1, i]的和之後通過減法我們可以O(1)時間獲得區間[i, j]的和,因此這個做法的時間複雜度爲O(n^2)。
然後這題的數據範圍較大,因此還需作進一步優化纔可以AC。記第i個元素爲a[i],定義dp[i]表示以下標i結尾的區間的最大和,那麼dp[i]的計算有2種選擇,一種是含有a[i-1],一種是不含有a[i-1],前者的最大值爲dp[i-1]+a[i],後者的最大值爲a[i]。而兩者取捨的區別在於dp[i-1]是否大於0。
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long int LL;
int a[10001];
int dp[10001];
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
for(int i=0; i<n; i++)
scanf("%d",&a[i]);
dp[0] = a[0];//邊界條件
int ans = dp[0], left=0, right=0;
for(int i=1; i<n; i++)
{
dp[i] = max(dp[i-1]+a[i], a[i]);
if(dp[i]>ans)
{
ans = dp[i];
right = i;
}
}
for(int i=right; ;i--)//找開始
{
ans-=a[i];
if(ans==0)
{
left = i;
break;
}
}
if(dp[right]>=0)
printf("%d %d %d\n",dp[right], a[left], a[right]);
else
printf("0 %d %d\n", a[0], a[n-1]);
}
return 0;
}