zoukankan      html  css  js  c++  java
  • 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
    */
    
  • 相关阅读:
    SQL入门学习4-复杂查询
    SQL入门学习3-数据更新
    SQL入门学习2-聚合与排序
    SQL入门学习1-查询基础
    SQL入门学习0-数据库与SQL
    Exp9 20155218 Web安全基础实践
    20155218《网络对抗》Exp8 Web基础
    # 20155218 徐志瀚 EXP7 网络欺诈
    Exp6 20155218 信息搜集与漏洞扫描
    20155218《网络对抗》MSF基础应用
  • 原文地址:https://www.cnblogs.com/czhui666/p/13715360.html
Copyright © 2011-2022 走看看