1. 程式人生 > 其它 >基礎演算法----字首和 and 差分

基礎演算法----字首和 and 差分

字首和

f[i] [j]為字首和陣列,a[i] [j]為原陣列

f[i] [j] = f[i-1] [j] + f[i] [j-1] - f[i-1] [j-1] + a[i] [j]

算區間字首和,畫個圖推公式

差分

原陣列a[i], 差分陣列f[i] = f[i] - f[i-1], f[1] = a[1]

性質1:差分陣列的字首和序列為a, 即差分陣列字首和s[i], s[i] = a[i];

性質2:給原陣列a區間在[l, r]各加d ,f[l] += d, f[r+1] -= d(減d則是f[l] -= d, f[r+1] += d), f其餘不變---->當對原陣列進行區間操作時,可以轉化成對差分陣列的單店操作

例:

給定一個長度為 n 的數列 a1,a2,…,an每次可以選擇一個區間 [l,r],使下標在這個區間內的數都加一或者都減一。

求至少需要多少次操作才能使數列中的所有數都一樣,並求出在保證最少次數的前提下,最終得到的數列可能有多少種。

輸入格式

第一行輸入正整數 n。

接下來 n 行,每行輸入一個整數,第 i+1行的整數代表 ai。

輸出格式

第一行輸出最少操作次數。

第二行輸出最終能得到多少種結果。

資料範圍

0<n≤105
0≤ai<2147483648

輸入樣例:

4
1
1
2
2

輸出樣例:

1
2

已知差分陣列性質2,每次可以令差分陣列中的一個數+1,另一個數-1,目的是將差分陣列b[2] - b[n]都變為0

先求出差分陣列b,令psum為b中的正數和,nsum為b中的負數和的絕對值,之後可以先進行min(psum, nsum)次,進行相平,之後還差|psum - nsum|下相平,可以再把這些數字和b1或b[n-1]進行相平(b[1]與b[n+1]的值不影響結果),因此總操作次數為min(psum, nsum) + |psum - nsum|, 而總結果種類可以為0到|psum - nsum|任意一種,因此總結果種數為|psum - nsum| + 1

程式碼示例:

ll a[100005];
ll b[100005];
ll n, nsum, psum;
ll ans;
ll cnt;

int main ()
{	
	cin >> n;
	For(i, 1, n) cin >> a[i];
	b[1] = a[1];
	For(i, 2, n) 
	{
		b[i] = a[i] - a[i-1];
		if(b[i] < 0) nsum += b[i];
		else psum += b[i];
	}
	nsum *= -1;

	ll tm = psum - nsum;
	if(tm < 0) tm *= -1;
	ans += min(psum, nsum);
	ans += tm;
   
	cnt = tm + 1;
	cout << ans << endl << cnt << endl;
	return 0;
}