2023.3.7

其实是 3.4 那天的模拟赛,那天打的挺崩溃来着,但是后来停电了(就很乐),于是比赛没打完,然后一直没来电就提前放学了捏。今天重赛了,来写写。


T1 洛谷:P1169 [ZJOI2007]棋盘制作

参考了洛谷大佬的题解。tql。

思路:找到符合 0101 这样的最大长方形和正方形。垂线法 dp:记录每个格子 (i, j) 最右端的障碍点、最左端的障碍点、上下能拓展的长度,即垂线标注,分别用 l[i][j],r[i][j],up[i][j] 表示。

1.初始化:从列的角度根据之前的分别初始记录障碍点,注意边界。

2.一边计算一边更新:从行的角度根据之前的分别更新障碍点。up 向下拓展。

方程 : l[i][j] = max(l[i][j], l[i - 1][j]), r[i][j] = min(r[i][j], r[i - 1][j]), up[i][j] = up[i - 1][j] + 1。

至于为什么是 max l 和 min r,可以画图理解,这个就是之前在列处理时,有的地方并没有考虑到行的状态,所以更新准确的障碍点位置。

3.一些脑残的小问题捏:注意区分长和宽;特别注意最后输出时是换行还是空格,有的 sb 题(例如本题)会卡,还是严谨一些好。

#include<bits/stdc++.h>
using namespace std;
const int N = 2010;
int n, m;
int x, y, ans1 = 0, ans2 = 0;
int a[N][N], l[N][N], r[N][N], up[N][N];
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++ )
        for(int j = 1; j <= m; j ++ )
        {
            scanf("%d", &a[i][j]);
            l[i][j] = r[i][j] = j;
            up[i][j] = 1;
        }
    for(int i = 1; i <= n; i ++ )
        for(int j = 2; j <= m; j ++ )
            if(a[i][j] != a[i][j - 1])
                l[i][j] = l[i][j - 1];
    for(int i = 1; i <= n; i ++ )
        for(int j = m - 1; j >= 1; j -- )
            if(a[i][j] != a[i][j + 1])
                r[i][j] = r[i][j + 1];
    for(int i = 1; i <= n; i ++ )
        for(int j = 1; j <= m; j ++ )
        {
            if(i > 1 && a[i][j] != a[i - 1][j])
            {
                l[i][j] = max(l[i][j], l[i - 1][j]);
                r[i][j] = min(r[i][j], r[i - 1][j]);
                up[i][j] = up[i - 1][j] + 1;
            }
            x = r[i][j] - l[i][j] + 1;
            y = min(up[i][j], x);
            ans1 = max(ans1, y * y);
            ans2 = max(ans2, x * up[i][j]); 
        }
    printf("%d\n%d", ans1, ans2);
    return 0;
}


T2 bzoj 2086 Blocks

由于 bzoj 好像很久之前就寄了,所以这里光放一下题面捏。

image

本题正解:dp + 单调栈(甚至不算 dp )。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6 + 10;
int n, m;
ll k;
ll a[N], sum[N];
int sta[N], top = 0;
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
    while(m -- )
    {
        scanf("%lld", &k);
        int ans = 0;
        top = 0;
        for(int i = 1; i <= n; i ++ ) {
            sum[i] = sum[i - 1] + a[i] - k;
            if(sum[i] < sum[sta[top]]) sta[++ top] = i;
        }
        sta[top + 1] = N;
        for(int i = n; i >= 1; i -- ) {
            while(top && sum[i] - sum[sta[top - 1]] >= 0) top--;
            ans = max(ans, i - sta[top]);
        }
        printf("%d\n", ans);
    }
    return 0;
}
posted @ 2023-03-07 20:59  Moyyer_suiy  阅读(22)  评论(0编辑  收藏  举报