1. 程式人生 > >【bzoj3043】IncDec Sequence 差分

【bzoj3043】IncDec Sequence 差分

整數 ... font 結果 兩個 ++ pre span cnblogs

題目描述

給定一個長度為n的數列{a1,a2...an},每次可以選擇一個區間[l,r],使這個區間內的數都加一或者都減一。
問至少需要多少次操作才能使數列中的所有數都一樣,並求出在保證最少次數的前提下,最終得到的數列有多少種。

輸入

第一行一個正整數n
接下來n行,每行一個整數,第i+1行的整數表示ai。

輸出

第一行輸出最少操作次數
第二行輸出最終能得到多少種結果

樣例輸入

4
1
1
2
2

樣例輸出

1
2


題解

差分

把原序列差分,考慮所有的$a_i-a_{i-1}(1\le i\le n+1)$,當$i\neq1$且$i\neq n+1$是都需要等於0。因此統計一下需要加多少次、減多少次。由於要求操作次數最少,因此其中的加減需要抵消。

即如果有$s1$次減操作、$s2$次加操作,那麽需要有$min(s1,s2)$次操作選出其中的兩個抵消。由於是差分數組,對應到原序列中就是區間+1或-1。

剩下的操作可以選擇用$a_1-a_0$或者$a_{n+1}-a_n$。選擇$a_1-a_0$的話相當於序列的值改變,否則不改變。因此序列改變的範圍是$[0,|s1-s2|]$,取值的範圍再+1即可。

因此只需要統計出每一個數與前一個數差了多少即可。

時間復雜度$O(n)$

#include <cstdio>
typedef long long ll;
int main()
{
	int n , i;
	ll x , y , s1 = 0 , s2 = 0;
	scanf("%d%lld" , &n , &x);
	for(i = 2 ; i <= n ; i ++ )
	{
		scanf("%lld" , &y);
		if(x < y) s1 += y - x;
		else s2 += x - y;
		x = y;
	}
	if(s1 < s2) printf("%lld\n%lld\n" , s2 , s2 - s1 + 1);
	else printf("%lld\n%lld\n" , s1 , s1 - s2 + 1);
	return 0;
}

【bzoj3043】IncDec Sequence 差分