回味尺取法(下)例題:poj3320

例題:http://poj.org/problem?id=3320

題目大意:jessica開始讀一本很厚的書,需要把書中所有知識點都掌握,這本書總共p頁,第i頁恰好有一個知識點ai,(每個知識點都有一個整數編號)全書中同一個知識點可能會被多次提到,所以他希望通過閱讀其中連續的一些頁把所有的知識點都覆蓋到,給定沒有人寫到的知識點,求出閱讀的最少頁數。

樣例:p=5,a={1.8.8.8.1},輸出:2

思路分析:

在某個區間[s,t]已經覆蓋了所有的知識點的情況下,下一個區間[s+1,t']要如何求出呢?

所有的知識點被覆蓋《=》每個知識點出現的次數都不小於1;

由於以上等價關係,我們可以用二叉樹等數據結構來儲存[s,t]區間上每個知識點出現的次數,這樣把最開頭的頁s去除後便可以判斷[s+1,t]是否滿足條件。

從區間把最開頭取出後,頁s上出現的知識點的出現次數就要減一,如果此時這個知識點的出現次數爲0的話,在同一個知識點出現之前一直不斷將區間末尾t向後退即可,每次在區間末尾追加t頁時將t頁上的知識點出現次數+1即可,這樣就完成了下一個區間上各個知識點出現次數的更新,通過重複這一操作可以以0(plogp)的複雜度求出最小的區間。

int p;
int a[MAX_P];
void solve() {
	//計算全部知識點的總和;
	set<int> all;
	for (int i = 0; i < p; i++)
		all.insert(a[i]);
	int n = all.size();
	//利用尺取法來解決;
	int s = 0, num = 0, t = 0;
	map<int, int> count;
	int res = p;
	for (;;) {
		while (t < p && num < n) {
			if (count[a[t++]]++ == 0)//出現新的知識點
				num++;
		}
		if (num < n)break;
		res = min(res, t - s);
		if (--count[a[s++]] == 0)//某個知識點出現的次數變爲0
			num--;
	}
	cout << res << endl;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章