1. 程式人生 > 其它 >【NOIP2017提高A組集訓10.21】Dark

【NOIP2017提高A組集訓10.21】Dark

技術標籤:題解

Dark

題目描述

Description

LichKing 希望收集邪惡的黑暗力量,並依靠它稱霸世界。
世間的黑暗力量被描述成一個長度為N 的非負整數序列{Ai},每次它可以選擇這個序列中的兩個相鄰的正整數,讓他們的值同時減一併獲得一點邪惡力量,直到不存在滿足條件的數。
然而你不希望他能夠得逞,所以你會使得他收集的能量儘可能少。

Input

N
A1 A2 … AN

Output

輸出一行一個整數,表示答案。

Sample Input

10
2 0 1 2 0 0 0 0 0 0

Sample Output

1

Data Constraint

在這裡插入圖片描述

思路

這題可以考慮用dp來做。
f i f_i fi表示 i i i這個位置要取完且 1 1 1~ i i i都合法。
因為是兩個連續的數,所以可以考慮從三個位置轉移。
1. f i − 1 f_{i-1} fi1轉移。由於要將連續兩個取完,即 f i = f i − 1 + a i f_i=f_{i-1}+a_i fi=fi1+ai
2. f i − 2 f_{i-2} fi2轉移。表示空一個取,即 f i = f i − 2 + a i f_i=f_{i-2}+a_i

fi=fi2+ai
3. f i − 3 f_{i-3} fi3轉移。表示空兩個取,即 f i = f i − 3 + m a x ( a i − 1 , a i ) f_i=f_{i-3}+max(a_{i-1},a_i) fi=fi3+max(ai1,ai)。因為必須i和i-1都取完,才能夠保證i-2和i-1不連著。
將上述轉移式整合一下,就可得
f i = m i n ( m i n ( f i − 1 + a i , f i − 2 + a i ) , f i − 3 + m a x ( a i − 1 , a i ) ) f_i=min(min(f_{i-1}+a_i,f_{i-2}+a_i),f_{i-3}+max(a_{i-1},a_i))
fi=min(min(fi1+ai,fi2+ai),fi3+max(ai1,ai))

但你會發現一些interesting的問題
如:
……4 3 6 2……,當執行到6時,你會發現不可能取6個,最多隻能取5個,那會不會影響答案呢?
並不會,因為錯誤的計算算出來的答案會多,自然會比正確情況的答案多,而正解又包含在我們推導的三個情況裡,所以正解會篩掉錯誤的計算。

Code

#include<cstdio>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
int n,a[100005],f[100005];
int main()
{
	fre(dark);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	f[1]=a[1],f[2]=a[2];
	for(int i=3;i<=n;i++)
		f[i]=min(min(f[i-1]+a[i],f[i-2]+a[i]),f[i-3]+max(a[i],a[i-1]));
	printf("%d",min(f[n-1],f[n]));
}