1. 程式人生 > >Sliding Window

Sliding Window

下標 gpo cst sin cstring 定時 最大 正常的 自己

poj2823 Sliding Window

    題目大意:給你一個n個數的序列,有一個長度固定的窗口,求出兩個數列,分別是窗口從左滑到右,窗口內的最小值和最大值,分兩行輸出。

    註釋:n<=$10^6$,內存<=64.

      想法:這內存是真惡心啊,正常的ST算法過不去,想到線段樹,......咳咳,雖然這道題可以用單調隊列和線段樹沒有什麽障礙的A掉,但是今天我們仍然用ST維護RMQ來解決。首先,我們對內存有一定的限制,但是我們有一個極好的條件,那就是窗口的大小是固定的。所以,不難發現,我們所用到的f[i][j]數組只用到了最後一維,那麽,我們想辦法壓維。壓維最根本的是可否可行在於動態規劃更新時是否有後效性。所以,我們就看一看。首先,我們顯然知道,更新一個f的值所用到的,一定有一個是它自己,還有一個就是往後$2^{j-1}$所代表的值,不難發現,這兩個下表都不小於i。所以,我們在從左向右松弛1-n時,所用到的下標都是沒有被這一輪更新的,也就是說,是沒有後效性的,故此,我們壓維是可以的。所以,這道題就A掉了。

    在此,我們有一個東西,就是log數組是不需要占用一個數組的內存的,我們發現,我們窗口固定時,log所提取的數也是固定的,那麽我們就可以在預處理時順便將log的值附好,即可。

    最後,附上醜陋的代碼... ...

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #define N 1000010
 5 using namespace std;
 6 int a[N];
 7 int f[N],g[N];
 8 int main()
 9 {
10 int n,len; 11 int maxlog; 12 while(~scanf("%d%d",&n,&len)) 13 { 14 // memset(f,0,sizeof(f)); 15 // memset(g,0,sizeof(g)); 16 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 17 for(int i=1;i<=n;i++)//初始化 18 { 19 f[i]=a[i];
20 g[i]=a[i]; 21 } 22 maxlog=0;//這點賊重要,我們發現如果len==1,maxlog沒有值??! 23 for(int i=1;(1<<i)<=len;i++) 24 { 25 maxlog=i; 26 for(int j=1;j+(1<<i)-1<=n;j++) 27 { 28 f[j]=max(f[j],f[j+(1<<(i-1))]); 29 g[j]=min(g[j],g[j+(1<<(i-1))]); 30 } 31 } 32 // cout<<"maxlog="<<maxlog<<endl; 33 // for(int i=1;i+(1<<maxlog)-1<=n;i++) 34 // { 35 // cout<<"f["<<i<<"]="<<f[i]<<endl; 36 // } 37 for(int i=1;i<=n-len+1;i++) 38 { 39 printf("%d ",min(g[i],g[i+len-(1<<maxlog)])); 40 } 41 printf("\n");//別忘記分行 42 for(int i=1;i<=n-len+1;i++) 43 { 44 printf("%d ",max(f[i],f[i+len-(1<<maxlog)])); 45 } 46 printf("\n"); 47 } 48 }

    小結:RMQ的點還有很多,還是那句話,倍增的想法的重要性要超過這個算法本身。

      錯誤:1.maxlog的初始化,極其重要。

         2.在初始化時,註意端點的位置。

Sliding Window