連號區間數(2013年第四屆c/c++ b組第10題)


題目描述

標題:連號區間數

小明這些天一直在思考這樣一個奇怪而有趣的問題:

在1~N的某個全排列中有多少個連號區間呢?這里所說的連號區間的定義是:

如果區間[L, R] 里的所有元素(即此排列的第L個到第R個元素)遞增排序后能得到一個長度為R-L+1的“連續”數列,則稱這個區間連號區間。

當N很小的時候,小明可以很快地算出答案,但是當N變大的時候,問題就不是那么簡單了,現在小明需要你的幫助。

輸入格式:
第一行是一個正整數N (1 <= N <= 50000), 表示全排列的規模。
第二行是N個不同的數字Pi(1 <= Pi <= N), 表示這N個數字的某一全排列。

輸出格式:
輸出一個整數,表示不同連號區間的數目。

示例:
用戶輸入:
4
3 2 4 1

程序應輸出:
7

用戶輸入:
5
3 4 2 5 1

程序應輸出:
9

解釋:
第一個用例中,有7個連號區間分別是:[1,1], [1,2], [1,3], [1,4], [2,2], [3,3], [4,4]
第二個用例中,有9個連號區間分別是:[1,1], [1,2], [1,3], [1,4], [1,5], [2,2], [3,3], [4,4], [5,5]

 

解題過程(其實這道題很簡單,請沒思路的朋友耐心

看下去,也可以直接先看最后面的代碼,很短,看完

代碼或許你就懂了

 

首先考慮時間復雜度:數據規模N<=50000,而我們要解這道題必定要遍

歷所有的子數組,所以時間復雜度最大為N(N-1)/2,大約是12.5億,也

就是N最大時程序要運行12秒(這還是保守估計),因為計算機每秒我

們都認為計算一億次左右,而題目要求要在5秒之內完成,這幾乎不可能

完成的,所以我們猜測實際出題者實際給出的樣例並不太接近50000。

 

 

走不通的動態規划思路:

一開始解決這道題的思路是“動態規划”,所以一直在思考較小的區間與包含這個區間的較大區間之間的聯系:

考慮以下樣例:

[3, 4, 2, 5, 1]

顯然對於包含單個元素的子數組來說肯定符合連號區間的定義,即[3],[4],[2],[5],[1]都是連號區間。

那我們來考慮[3,4]是不是連號區間是否與[3],[4]是連號區間有關,這里[3,4]、[3]、[4]恰好都是

連號區間;

繼續考慮[4,2]是不是連號區間是否與[4]、[2]是連號區間有關,顯然雖然[4]和[2]都是連號區間,

[4,2]並不是連號區間,經過仔細考慮,我找不到任何可以用動態規划的痕跡,所以轉換了思路。

 

轉換思路,考慮暴力破解?用哪種方法判斷一個子數組是否符合

連號區間開銷最小?

還是考慮[3, 4, 2, 5, 1]這個樣例,我們先把它排個序,這樣看起來直觀些:

[1, 2, 3, 4, 5]

由於數據元素是有序且唯一的(不存在一個數組里面有兩個元素相等),所以我們會驚喜地發現

當一個數組是連號區間時,有:

數組最大值 - 數組最小值 + 1 = 數組元素個數

我們記為: max - min + 1 = len;

證明max - min + 1 = len

假設一個長度為len的數組為A = {a1, a2, a3, ..., an};

我們干脆就假設數組最小元素min = a1,假設

數組最大元素max = an;

那怎樣使得A數組滿足連號區間呢,根據

連號區間的定義,該數組必須要有min + 1, min + 2,...,

max - 1這些數組元素(一共max - min - 1 個數),

這樣就要求數組元素必須有(max - min + 1)

個數(包括最大元素和最小元素)才能滿足連號區間。

而實際上A數組不一定是有max - min + 1個數組元素的,

這種情況下A數組就不滿足連號區間。

舉個栗子

如果你還不明白我在說什么,那應該是我表達能力太差了,

這樣吧,我們舉個栗子:

考慮以下數據

[3, 4, 2, 7, 1]

這個數組最大值為7,最小值為1,那你想一想,如果要讓該數組滿足

連號區間的定義,必然還要有2,  3,  4, 5, 6這幾個數組元素才滿足對吧,

即數組元素個數必定是7個元素(包括最大值和最小值)才滿足連號

區間,而[3, 4, 2, 7, 1]實際才有5個元素,這樣明顯[3, 4, 2, 7, 1]就不符合

連號區間的定義。

 

accept代碼

 

#include <cstdio>
#include <iostream>
using namespace std;
int num[50000 + 10];


int main()
{
	int count = 0;
	int N;
	cin >> N;
	count += N;  //只有一個元素的子數組明顯符合條件 ,一共有N個只有一個元素的子數組 
	for(int i = 0; i < N; i++)
	{
		cin >> num[i];
	}

	//遍歷所有子數組,如果子數組滿足“最大元素 - 最小元素 + 1 == 數組長度”,則說明滿足連號區間條件,count++。 
	for(int i = 0; i < N; i++)
	{
		int min = num[i];
		int max = num[i];
		for(int j = i + 1; j < N; j++)
		{
			if(min > num[j])
			{
				min = num[j];
			}
			if(max < num[j])
			{
				max = num[j];
			}
			if(max - min == j - i)
			{
				count++;
			}
		}
	}
	cout << count << endl;
	
	return 0;
}

 

  

 如果哪里總結錯了,希望各位朋友不吝賜教!!!

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com