0922考试T4 区间DP

0922考试T4

​ 题目描述:

​ 机房所有的电脑构成了一个\(n*n\)的矩阵,每一台电脑都有一个便利值\(a[i][j]\),在这个矩形里找两个互不重叠的矩形,并且这两个矩形的便利值之和为\(p\)的倍数,问对多可以选出多少个电脑。

​ 区间DP。

​ 我们先对每行求一个前缀和。然后用\(l, r\)从纵方向框住一部分,\(g[l]\)表示在\(l\)右边的最大矩形,\(f[r]\)表示紧贴着\(r\)并且在\(r\)左边的最大矩形。

​ 而且我们可以知道,如果左右区间相同,上界为1,下界不同的两个矩形,他们的便利值对\(p\)取模后相同,说明这两个矩形的下界框住的这个矩形的便利值一定是\(p\)的倍数。

​ 然后把矩形顺时针反转一下再做一遍相同操作就好了。

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}

const int N = 305;
int n, p, tmp, ans;
int a[N][N], f[N], g[N], sum[N][N], tong[55];

void clear() {
    memset(f, 0, sizeof(f)); 
    memset(g, 0, sizeof(g));
    memset(sum, 0, sizeof(sum));
}

void calc() {
    clear();
    for(int i = 1;i <= n; i++) 
        for(int j = 1;j <= n; j++) sum[i][j] = sum[i][j - 1] + a[i][j];
    
    for(int len = 1;len <= n; len ++) {
        for(int l = 1;l + len - 1 <= n; l++) {
            int r = l + len - 1;
            memset(tong, -1, sizeof(tong)); tong[0] = 0;
            int tmp = 0;
            for(int i = 1;i <= n; i++) {
                tmp += sum[i][r] - sum[i][l - 1];
                tmp %= p;
                if(tong[tmp] == -1) tong[tmp] = i;
                else {
                    g[l] = max(g[l], (i - tong[tmp]) * len);
                    f[r] = max(f[r], (i - tong[tmp]) * len);
                }
            }
        }
    }
    for(int i = n - 1;i >= 1; i--) g[i] = max(g[i], g[i + 1]);
    for(int i = 1;i <= n - 1; i++) ans = max(ans, f[i] + g[i + 1]);
}

void turn() {
    int tmp[N][N];
    for(int i = 1;i <= n; i++)
        for(int j = 1;j <= n; j++) tmp[i][j] = a[i][j];
    
    for(int i = 1;i <= n; i++) 
        for(int j = 1;j <= n; j++) a[i][j] = tmp[j][i];
}

int main() {

    freopen("matrix.in","r",stdin); freopen("matrix.out","w",stdout);

    n = read(); p = read();
    for(int i = 1;i <= n; i++) 
        for(int j = 1;j <= n; j++) a[i][j] = read();

    calc(); turn(); calc();

    printf("%d", ans);

    fclose(stdin); fclose(stdout);
    return 0;
}
/*
5 6
7 2 3 1 1
5 0 6 0 0
8 6 6 5 3
4 3 7 8 2
4 0 0 6 9
*/
posted @ 2020-09-22 22:48  C锥  阅读(139)  评论(1编辑  收藏  举报