例題: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;
}