[校内自测 NOIP模拟题] chenzeyu97要请客(单调栈)

chenzeyu97要请客 submatrix

##【题目描述】:

众所周知,哲学家chenzeyu97由于在前面的许多场比赛中都取得了优异成绩!所以他在这场赛后要请客!

chenzeyu97的家可以看成是一个n*m的矩阵,每块区域都有独一无二的海拔高度h(h>0)!其最大值为n*m。现在他要选择一个子矩阵摆放一张桌子,在他眼里,这样摆放桌子的美观度为这个子矩阵的最小值,他想知道,如果他要求摆放桌子的美观度为i,那么可以选择多少种子矩阵呢?对于所有可能的i值(1<=i<=n*m),你都应该得出其方案数,这样你就能顶替蒟蒻hzwer获得被请客的资格!

##【输入描述】:

第一行两个整数n,m;

接下来n行,每行m个整数,描述chenzeyu97的家。

##【输出描述】:

n*m行,每行一个整数,第i行表示美观度i的方案数

##【样例输入】:

2 3

2 5 1

6 3 4

##【样例输出】:

6

4

5

1

1

1

##【时间限制、数据范围及描述】:

时间2s 空间:256M

30%的数据1<=n,m<=50

100%的数据1<=n,m<=300

laj有点懵……hzwer的f数组的用途没弄明白 _(:зゝ∠)_ 算合并两个矩阵最后得出的总个数貌似是原来两个矩阵的个数的乘积趴qwq

来自hzwer的题解 Orz

首先肯定要枚举左右边界L-R吧。。。

我们知道每一行L-R的最小值,这个可以从L-1-R在O1的时间内转移

然后考虑在行上统计答案

问题转换为一个数列,要在On的时间内统计出每个子区间最小值

对于每个数a[x],我们只要知道前一个比它小的数a[y],则a[y+1]到a[x-1]在x之后都不重要了

可以用一个a[x]和f[x]来替代他们,将a[x]和f[x]放入单调栈

具体过程是:如果要加入一个点i,只要栈顶最小值比它大,就不停地把栈顶并给i,同时考虑对答案的影响

粘上跟hzwer近乎一模一样的程序 Orz

 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 inline int read(){
 9     int an=0,x=1;char c=getchar();
10     while (c<'0' || c>'9') {if (c=='-') x=-1;c=getchar();}
11     while (c>='0' && c<='9') {an=an*10+c-'0';c=getchar();}
12     return an*x;
13 }
14 void calc(){
15     int i,j;LL sum;
16     top=0;
17     for (i=1;i<=n;i++){
18         f[i]=1;sum=1;
19         while (top && mn[i]<mn[sta[top]]){
20             ans[mn[sta[top]]]+=f[sta[top]]*sum;
21             sum+=f[sta[top]];
22             f[i]+=f[sta[top]];
23             top--;
24         }
25         sta[++top]=i;
26     }
27     sum=0;
28     while (top){
29         ans[mn[sta[top]]]+=f[sta[top]]*(sum+1);
30         sum+=f[sta[top]];
31         top--;
32     }
33 }
34 int main(){
35     freopen ("submatrix.in","r",stdin);
36     freopen ("submatrix.out","w",stdout);
37     int i,j,k;
38     n=read();m=read();
39     memset(ans,0,sizeof(ans));memset(f,0,sizeof(f));
40     for (i=1;i<=n;i++)
41         for (j=1;j<=m;j++)
42             a[i][j]=read();
43     for (i=1;i<=m;i++){
44         memset(mn,127,sizeof(mn));
45         for (j=i;j<=m;j++){
46             for (k=1;k<=n;k++)
47                 mn[k]=min(mn[k],a[k][j]);
48             calc();
49         }
50     }
51     for (i=1;i<=n*m;i++)
52         printf("%d
",ans[i]);
53     return 0;
54 }
未来是什么样,未来会发生什么,谁也不知道。 但是我知道, 起码从今天开始努力, 肯定比从明天开始努力, 要快一天实现梦想。 千里之行,始于足下! ——《那年那兔那些事儿》
原文地址:https://www.cnblogs.com/keximeiruguo/p/7689849.html