Cpp環境【POJ3320】Jessica's Reading Problem 潔西卡的複習計劃

Description  【問題描述】

Jessica’s a very lovely girl wooed by lots of boys. Recently she has a problem. The final exam is coming, yet she has spent little time on it. If she wants to pass it, she has to master all ideas included in a very thick text book. The author of that text book, like other authors, is extremely fussy about the ideas, thus some ideas are covered more than once. Jessica think if she managed to read each idea at least once, she can pass the exam. She decides to read only one contiguous part of the book which contains all ideas covered by the entire book. And of course, the sub-book should be as thin as possible.
A very hard-working boy had manually indexed for her each page of Jessica’s text-book with what idea each page is about and thus made a big progress for his courtship. Here you come in to save your skin: given the index, help Jessica decide which contiguous part she should read. For convenience, each idea has been coded with an ID, which is a non-negative integer.


  (省略無數無關詞)爲準備考試,Jessica開始閱讀一本很厚的課本。要想通過考試,她必須把課本中所有知識點都掌握。這本書總共有P頁,第i頁恰好有一個知識點a[i](每個知識點都有一個整數編號)。全書中同一個知識點可能會被多次提到,所以她希望通過閱讀其中連續的一些頁把所有的知識點都覆蓋到。給定每頁寫到的知識點,請求出要閱讀的最少頁數。

Input  【輸入格式】

The first line of input is an integer P (1 ≤ P ≤ 1000000), which is the number of pages of Jessica’s text-book. The second line contains P non-negative integers describing what idea each page is about. The first integer is what the first page is about, the second integer is what the second page is about, and so on. You may assume all integers that appear can fit well in the signed 32-bit integer type.


  第一行一個整數P,表示書本的總頁數。接下來的一行,包含P個整數,第i整數表示第i頁包含的知識點的編號。

Output  【輸出格式】

Output one line: the number of pages of the shortest contiguous part of the book which contains all ideals covered in the book.


  一個整數,表示需要閱讀的最少連續頁數

Sample Input  【輸入樣例】

5
1 8 8 8 1

Sample Output  【輸出樣例】

2

【數據範圍】  

1<=P<=10^6 , 1<=a[i]<=10^9

【來源】

POJ3320

【思路梳理】

  一個變形後的滑動窗口應用問題,要求的是滑動窗口的最小長度,使得在這個滑動窗口內有全集中的任意一個元素。顯然滑動窗口在長度最小且滿足該條件時,每個元素可能有多個。
  首先考慮存儲的容器。因爲需要對每個元素——知識點的序號的種類數進行統計,而這個序號可能會很大(高達10的9次方),顯然用map映射(“超級數組”)來存儲比較穩妥,將無序的知識點的序號映射到該序號在滑動窗口中出現的次數。
  在滑動窗口的元素種類數小魚總的知識點數的時候,只需要把這一頁所對應的知識點進map就可以,若該頁對應的知識點爲i,那麼map[a[i]]++。
  當滑動窗口中的元素的種類數等於總的知識點數的時候,我們就檢查能否縮短滑動窗口的長度(用s和d分別標記滑動窗口的起點和終點),即map[a[s]]是否大於1,如果爲真就說明滑動窗口可以右移並且重複此判斷,若否就停止。對於每一個時刻我們都用一個ans來取一個最小的滑動窗口長度(length=d-s+1)即可。
  這個題的數據最後兩組非常大,一定要把各種優化加上!
【Cpp代碼】

#include<map>
#include<cstdio>
#define inf 2000000005
#define maxn 1000005
using namespace std;
int tot,p,ans=inf,a[maxn];
map<int,int>mp;

int read()//手工讀入防止超時
{
    char ch=getchar();bool ok=false;int cnt=0;
    while((ch<'0' || ch>'9') && ch!='-')    ch=getchar();   
    while((ch>='0' && ch<='9') || ch=='-')
    {
        if(ch=='-') ok=true;
        else cnt=cnt*10+ch-'0';
        ch=getchar();
    }
    return ok? -cnt:cnt;
}
int min(int a,int b){if(a>b)return b;return a;}

void solve()
{
    mp.clear();
    int num=0,s=1;
    for(int i=1;i<=p;i++)//滑動窗口的終點爲i,起點爲s
    {
        mp[a[i]]++;//進滑動窗口
        if(mp.size()<tot)   continue;//滑動窗口中元素種類數沒有達到總的知識點個數
        if(a[i]==a[s])  mp[a[i]]--,s++;//起點和終點相同,直接把起點往右側挪
        while(mp[a[s]]>1 && s!=i)//若起點頁碼對應的知識點出現多次,那麼就可以不斷把起點往右移
        {           
            mp[a[s]]--;
            s++;
        }
        ans=min(ans,i-s+1);//記錄最小長度
    }
    printf("%d",ans);
}

int main()
{
//  freopen("input10.txt","r",stdin);
    p=read();   
    for(int i=1;i<=p;i++)   { a[i]=read();mp[a[i]]++; }
    tot=mp.size();
    solve();
    return 0;
}
發佈了59 篇原創文章 · 獲贊 10 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章