p3686 最大子段和
時間限制 :
- ms
空間限制 :
65536 kb
問題描述
給你乙個包含n個整數的序列,要求從中取出m個不相交的子段,要求這m個子段的和盡肯能大,輸出這個最大和。
例如,n=7,m=2, 序列如下:
-2 1 4 -2 3 -2 3
最優方案取出的兩段為 這兩段的和為9
輸入格式
第一行,兩個整數n和m
第二行,n個空格間隔的整數,表示整數數列
輸出格式
一行,乙個整數,表示所求答案
樣例輸入
7 2-2 1 4 -2 3 -2 3
樣例輸出9
提示1<=n <=100,000 1<=m<=300 且 m<=n
數列中的數字範圍[-50000,50000]
我們可以發現這是一道動規,用f[i][j]表示前i個數分j段的最大和
我們再用sum做輸入陣列的字首和
那麼我們可以得到以下動規方程:
fi[j]=max(f[i-1][j],f[k][j-1]+sum[i]-sum[k])
即要麼放棄這個數(情況1),要麼將第k+1到第i個分成一段(情況2),轉移方程就完成了
然後我們想,f[i][j]要開到f[100005][305]大概120m,無法滿足題目的要求,因此我們應該使用滾動陣列
我們發現f[i][j]只與j和j-1有關,所以我們在使用陣列的時候只用討論j%2的情況即可
但是由於資料範圍較大,根據上面的動規方程我們要進行三次迴圈,所以需要優化演算法效率
在討論f[k][j-1]+sum[i]-sum[k]時,由於i相對於k是乙個常數,所以我們可以用乙個best[j]陣列記錄在討論將i個數分成j段時情況2的最大和,從而消掉k的迴圈
後來發現當輸入的資料都為負數時,由於演算法的不完美性,得出了錯誤答案,因此總結得出若輸入的全是負數,則輸出最大的m個數的和
#include#include#includeusing namespace std;
const int inf=2e9;
int a[100005],f[100005][2],sum[100005],best[305];
bool cmp(int a,int b)
int main()
if(flag){
int sum=0;
sort(a+1,a+1+n,cmp);
for(i=1;i<=m;i++)sum+=a[i];
cout<
例題 動規 NKOJ 3686 最大子段和
nkoj 3686 最大子段和 時間限制 ms 空間限制 65536 kb 問題描述 給你乙個包含n個整數的序列,要求從中取出m個不相交的子段,要求這m個子段的和盡肯能大,輸出這個最大和。例如,n 7,m 2,序列如下 2 1 4 2 3 2 3 最優方案取出的兩段為 這兩段的和為9 輸入格式 第一...
最大子段和
設a 是n個整數的序列,稱為該序列的子串行,其中1 i j n.子串行的元素之和稱為a的子段和.例如,a 2,11,4,13,5,2 那麼它的子段和是 長度為1的子段和 2,11,4,13,5,2 長度為2的子段和 9,7,9,8,7 長度為3的子段和 5,20,4,6 長度為4的子段和 18,15...
最大子段和
問題表述 n個數 可能是負數 組成的序列a1,a2,an.求該序列 例如 序列 2,11,4,13,5,2 最大子段和 11 4 13 20。1 窮舉演算法 o n3 o n2 2 分治法 將序列a 1 n 從n 2處截成兩段 a 1 n 2 a n 2 1 n 例項 三 最大子段和 問題表述 n個...