|
发表于 2023-8-9 14:58:46
|
显示全部楼层
本帖最后由 陶远航 于 2023-8-9 14:59 编辑
单调栈
先输入数据
处理处每个点往上一共有多少个连续的没有被画过的点
然后每一行f[i][0]和f[i][m + 1]要赋值一个超级小的数
为了让区间边界终止与此
然后顺序扫一遍找出每一个点
左边距离他最近的一个比他矮的点
然后倒叙扫一遍找出每一个点
右边距离他最近的一个比他矮的店
中间的就是它能够构成的矩阵
矩阵组成方式是
左边区间的长度(包括中间点) * 右边区间的长度(包括中间点) * 宽(也就是f[i][j])
累加起来输出就好了
- #include<iostream>
- #include<cstdio>
- #include<stack>
- #define int long long
- using namespace std;
- const int Max = 1005;
- int f[Max][Max];
- int a[Max];
- int r[Max],l[Max];
- signed main()
- {
- char c;
- int n,m;
- cin >> n >> m;
- for(register int i = 1;i <= n;++ i)
- {
- for(register int j = 1;j <= m;++ j)
- {
- cin >> c;
- if(c == '*')f[i][j] = 0;
- else
- f[i][j] = f[i - 1][j] + 1;
- }
- }
- for(int i = 1;i <= n;++ i)
- f[i][0] = f[i][m + 1] = -0x7fffffff;
- int ans = 0;
- for(register int i = 1;i <= n;++ i)
- {
- stack<int>s1,s2;
- s1.push(1),s2.push(m);
- for(register int ii = 2,jj = m - 1;ii <= m + 1,jj >= 0;jj --,++ ii)
- {
- while(!s1.empty() && f[i][ii] < f[i][s1.top()])
- {
- r[s1.top()] = ii;
- s1.pop();
- }
- while(!s2.empty() && f[i][jj] <= f[i][s2.top()])
- {
- l[s2.top()] = jj;
- s2.pop();
- }
- s1.push(ii);s2.push(jj);
- }
- for(register int j = 1;j <= m;++ j)
- ans += (j - l[j]) * (r[j] - j) * f[i][j];
- }
- cout << ans << endl;
- return 0;
- }
复制代码 |
|