zoukankan      html  css  js  c++  java
  • [校内自测 NOIP模拟题] chenzeyu97要请客(单调栈)

    题目描述

    chenzeyu97的家可以看成是一个n*m的矩阵,每块区域都有独一无二的海拔高度h(h>0)!其最大值为n*m。 

    现在他要选择一个子矩阵摆放一张桌子,在他眼里,这样摆放桌子的美观度为这个子矩阵中所有元素中值的最小值,他想知道,如果他要求摆放桌子的美观度为i,那么可以选择多少种子矩阵呢? 

    对于所有可能的i值(1≤i≤n*m),你都应该得出其方案数,这样你就能顶替蒟蒻hzwer获得被请客的资格! 

    题解:http://hzwer.com/4727.html 

    输入

    第1行:两个整数N,M; 

    接下来N行:每行m个整数,描述一个N*M的矩阵.  

    30%的数据1≤n,m≤50;  

    100%的数据1≤n,m≤300. 

    输出

    输出N*M行,每行一个整数,第i行表示美观度i的方案数. 

    样例输入 Copy

    2 3
    2 5 1
    6 3 4

    样例输出 Copy

    6
    4
    5
    1
    1
    1

    提示

    【样例解释】 

    美观度为1的情况: 

    在2*3的矩阵中,分别选择如下的子矩阵:选择第1行第3列、选择第1行第2列~第1行第3列、选择第1行第1列~第1行第3列、选择第1行第3列~第2行第3列、选择第1行第2列~第2行第3列、选择第1行第1列~第2行第3列,其美观度均为1,共6种情况; 

    美观度为2的情况: 

    在2*3的矩阵中,分别选择如下的子矩阵:选择第1行第1列、选择第1行第1列~第1行第2列、选择第1行第1列~第2行第1列、选择第1行第1列~第2行第2列,共4种情况。 

    以此类推… 

    思路

    • 这题是单调栈的题目,但用单调队列就会T,因为如果要用单调队列,就还要去枚举一下滑动窗口的长度,所以就多了一个n,所以就T掉了。
    • 讲一下正解,不用想,一定要去枚举左右区间,l->r.
    • 我们要知道每一个行区间l--->r的最小值,这个可以用l-1---->r 用O(1)转移过来。
    • 现在我们就要在行上去统计答案。
    • 现在原题就变成了如何对一个数列,用O(n)的时间复杂度去求出最小值
    • 此时我们只要知道当前的是A{X},前一个比他小的值是A[Y],然后这中间的一堆没用的东西就没用了。因为这里面的都没有对答案造成贡献,所以这区间的就可以不管了
    • 然后具体实现就是如果要把一个点放到单调栈里,只要栈顶的最小值比他大,就将栈顶给这个点,并不断统计答案的影响。
    • f数组表示当前的往前的最长区间,然后答案就是向前最大的长度*向后最大的长度(乘法原理,我一直以为是公式,然后被机房大佬疯狂嘲讽)
    • mn里存下预处理好的高度。
    • 然后放到单调栈里,不断的弹,然后就是统计答案了
    •  1 #include<bits/stdc++.h>
       2 using namespace std;
       3 typedef long long LL;
       4 const int MAX = 305;
       5 int n, m;
       6 int a[MAX][MAX], sta[MAX], top, mn[MAX];
       7 LL f[MAX], ans[MAX * MAX];
       8 
       9 int read()
      10 {
      11     char c;
      12     int num, f = 1;
      13     while (c = getchar(), !isdigit(c))
      14         if (c == '-')
      15             f = -1;
      16     num = c - '0';
      17     while (c = getchar(), isdigit(c))
      18         num = num * 10 + c - '0';
      19     return f * num;
      20 }
      21 void calc()
      22 {
      23     int i, j;//手动写一个单调栈,去模拟将一个点放入后的贡献。
      24     LL sum;
      25     top = 0;
      26     for (i = 1; i <= n; i++)
      27     {
      28         f[i] = 1;
      29         sum = 1;
      30         while (top && mn[i] < mn[sta[top]])
      31         {
      32             ans[mn[sta[top]]] += f[sta[top]] * sum;
      33             sum += f[sta[top]];
      34             f[i] += f[sta[top]];
      35             top--;
      36         }
      37         sta[++top] = i;
      38     }
      39     sum = 0;
      40     while (top)
      41     {
      42         ans[mn[sta[top]]] += f[sta[top]] * (sum + 1);
      43         sum += f[sta[top]];
      44         top--;
      45     }
      46 }
      47 int main()
      48 {
      49     int i, j, k;
      50     n = read();
      51     m = read();
      52     memset(ans, 0, sizeof(ans));
      53     memset(f, 0, sizeof(f));
      54     for (i = 1; i <= n; i++)
      55         for (j = 1; j <= m; j++)
      56             a[i][j] = read();
      57     for (i = 1; i <= m; i++)
      58     {
      59         memset(mn, 127, sizeof(mn));
      60         for (j = i; j <= m; j++)
      61         {
      62             for (k = 1; k <= n; k++)
      63                 mn[k] = min(mn[k], a[k][j]);//这就是一个简单的预处理,存的就是从l开始的每一个区间的高度
      64             calc();
      65         }
      66     }
      67     for (i = 1; i <= n * m; i++)
      68         printf("%d
      ", ans[i]);
      69     return 0;
      70 }

       

  • 相关阅读:
    linux nfs
    gsoap
    error: ignoring return value of 编译错误处理
    SSIS可靠性和扩展性—错误输出
    SSIS中的脚本—脚本组件
    SQL点滴24—监测表的变化(转载)
    SSIS中的脚本—脚本任务
    SSIS可靠性和扩展性—简介
    SSIS中的脚本—表达式
    SSIS可靠性和扩展性—可扩展性
  • 原文地址:https://www.cnblogs.com/2529102757ab/p/11832170.html
Copyright © 2011-2022 走看看