Luogu 2216 [HAOI2007]理想的正方形 (單調隊列優化)

題意:

    給出一個 N×M 的矩陣,以及一個數值 K ,求在給定的矩陣中取出一個 K×K 的矩陣其中最大值減去最小值的最小值。ios


細節:

    沒有細節來發暴力走天下,20分也是分啊~~~ QAQ。數組

 

分析:

    感受是一題裸體,大佬們看了必定秒切,可是本蒟蒻顯然不會,二維不易能夠先嚐試如何求解在 1×K 的矩陣中求解答案呢,顯然是利用一個數組 Max1[i][j] 表示第 i 行區間 [ j , j + K - 1] 的最大值,Min1[i][j] 表示第 i 行區間 [ j , j + K - 1] 的最小值,每行利用一個單調隊列進行定區間求最值的操做,最後 O(N×M) 的枚舉全部的 1×K 的矩陣,求解最小值便可。優化

  好吧此時你應該豁然開朗,這(TM <- 但願忽略這個東西)就是將一維的數組在進行一次求解,獲得二維數組的最值便可,仍然利用一個數組 Max2[i][j] 表示縱向區間 [i , i + K - 1]、橫向區間 [j , j + K - 1]中的最大值,Min2[i][j] 表示縱向區間 [i , i + K - 1]、橫向區間 [j , j + K - 1]中的最小值,只須要對上面一步操做的中的 Max1[][]、Min1[][]數組,每列利用一個單調隊列進行定區間求最值,一樣是 O(N×M) 的時間複雜度處理出了全部 K×K 的矩陣,最後只須要統計答案所指向的最優值便可。spa

  實際上本題也是含有少量 Dp 的思想,將大多的重複與沒必要要同過單調隊列的思想進行了優化,這應該是一道不錯的練手的模板題。code

 

代碼:

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 int n,m,k,front,FRONT,back,BACK,ans;
 5 int a[1001][1001],q[1001],Q[1001],x[1001][1001],X[1001][1001],y[1001][1001],Y[1001][1001];
 6 int main()
 7 {
 8     scanf("%d%d%d",&n,&m,&k);
 9     for (int I=1;I<=n;I++)
10         for (int i=1;i<=m;i++)
11             scanf("%d",&a[I][i]);
12     for (int I=1;I<=n;I++){
13         FRONT=BACK=front=back=Q[1]=q[1]=1;
14         for (int i=2;i<=m;i++){
15             while (a[I][i]>=a[I][Q[BACK]]&&FRONT<=BACK) BACK--;
16             while (a[I][i]<=a[I][q[back]]&&front<=back) back--;
17             BACK++;back++;Q[BACK]=i;q[back]=i;
18             while (i-Q[FRONT]>=k) FRONT++;
19             while (i-q[front]>=k) front++;
20             if (i>=k) X[I][i-k+1]=a[I][Q[FRONT]],x[I][i-k+1]=a[I][q[front]];
21         }
22     }
23     for (int I=1;I<=m-k+1;I++){
24         FRONT=BACK=front=back=Q[1]=q[1]=1;
25         for (int i=2;i<=n;i++){
26             while (X[i][I]>=X[Q[BACK]][I]&&FRONT<=BACK) BACK--;
27             while (x[i][I]<=x[q[back]][I]&&front<=back) back--;
28             BACK++;back++;Q[BACK]=i;q[back]=i;
29             while (i-Q[FRONT]>=k) FRONT++;
30             while (i-q[front]>=k) front++;
31             if (i>=k) Y[i-k+1][I]=X[Q[FRONT]][I],y[i-k+1][I]=x[q[front]][I];
32         }
33     }
34     ans=0x3f3f3f3f;
35     for (int I=1;I<=n-k+1;I++)
36         for (int i=1;i<=m-k+1;i++) ans=min(ans,Y[I][i]-y[I][i]);
37     printf("%d\n",ans);
38     return 0;
39 }

咳咳,此代碼代碼風格奇異,可能不是原創,請各位閱讀者諒解…… QWQ。blog

相關文章
相關標籤/搜索