zoukankan      html  css  js  c++  java
  • Luogu 2216 [HAOI2007]理想的正方形 (单调队列优化)

    题意:

        给出一个 N×M 的矩阵,以及一个数值 K ,求在给定的矩阵中取出一个 K×K 的矩阵其中最大值减去最小值的最小值。


    细节:

        没有细节来发暴力走天下,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 的矩阵,最后只需要统计答案所指向的最优值即可。

      实际上本题也是含有少许 Dp 的思想,将大多的重复与不必要同过单调队列的思想进行了优化,这应该是一道不错的练手的模板题。

    代码:

     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
    ",ans);
    38     return 0;
    39 }

    咳咳,此代码代码风格奇异,可能不是原创,请各位阅读者谅解…… QWQ。

  • 相关阅读:
    jsp%不能解析
    hibernate映射数据库时@ManyToOne和@OneToMany
    PSP需求分析文档
    医院挂号系统前景与范围文档
    PSP个人软件开发工具需求分析文档
    英雄联盟战队管理系统项目前景与范围文档
    在学习抛出异常的过程中,关于错误信息 TypeError: exceptions must derive from BaseException 的原因
    python面向对象__slots__变量的运用
    初学过程中,对于python if__name__=='main'的作用
    使用C模拟面向对象实现如java的LinkedList集合(好精彩)
  • 原文地址:https://www.cnblogs.com/xiannvzuimei/p/9983320.html
Copyright © 2011-2022 走看看