zoukankan      html  css  js  c++  java
  • 计蒜客 蒜头君打地鼠 (矩阵旋转 + 二维前缀和)


    链接 : Here!

    思路 :

    1. 首先看数据范围 $1leq n leq 2000$, $1 leq k leq 100$ , 直接暴力肯定 $T$, 如果锤子是正着的就好办了, 就可用二维前缀和的技巧来进行降维了!
    2. 所以直接将矩阵右旋45°, 让锤子正过来, 右旋时需要注意原坐标 $(x, y)$ 被映射为 $(x+y, n-1-x-y)$ 了, 原矩阵被放大为$(2n-1) * (2n-1)$ 了, 同时锤子也被放大为 $(2k-1) * (2k-1)$
    3. 直接扫描一遍二维数组, 计算一下二维前缀和, 然后枚举锤子的四个角, $O(1)$ 的时间内便能找到锤子所在范围中地鼠的个数了

    注意 : 这个数据好像有毒, 按道理来说锤子不一定全部落在原矩形内砸到的地鼠最多, 很有可能原矩形只有一条边上有地鼠, 因此如果想得到最大地鼠数的话, 锤子的一部分必须在外面, 但是我修改 $check$ 数组后反而通不过所有数据 QAQ


    代码 :

    /*************************************************************************
    	> File Name: 蒜头君打地鼠.cpp
    	> Author: 
    	> Mail: 
    	> Created Time: 2017年11月20日 星期一 19时58分35秒
     ************************************************************************/
    
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    
    #define MAX_N 4000
    
    int a[MAX_N][MAX_N];
    int sum[MAX_N][MAX_N];
    bool vis[MAX_N][MAX_N];
    int n, k, t_n;
    
    // 这个题有毒吧...
    // 注意旋转后矩阵和锤子都变大了
    // 这里旋转后的点并不是严格遵循数学中的旋转
    void read() {
        memset(a, 0, sizeof(a));
        memset(sum, 0, sizeof(sum));
        memset(vis, 0, sizeof(vis));
        scanf("%d%d", &n, &k);
        for (int i = 0 ; i < n ; ++i) {
            for (int j = 0 ; j < n ; ++j) {
                int temp;
                scanf("%d", &temp);
                a[i + j][n - 1 - i + j] = temp;
                vis[i + j][n - 1 - i + j] = 1;
            }
        }
        t_n = n;
        n = n * 2 - 1;
        k = k * 2 - 1;
        // 可以清晰的查看到矩阵被放大了
        // 旋转后矩阵的大小变为了原来的 (2 * n - 1) X (2 * n - 1)
        // 当然锤子也应该变大
        // 看起来是右旋45度
        // 
        // TODO 拓展问题 : 如果将矩阵左旋45度,旋转90度,旋转180度...等等
    }
    
    void cal_sum() {
        for (int i = 0 ; i < n ; ++i) {
            for (int j = 0 ; j < n ; ++j) {
                if (i > 0) sum[i][j] += sum[i - 1][j];
                if (j > 0) sum[i][j] += sum[i][j - 1];
                if (i > 0 && j > 0) sum[i][j] -= sum[i - 1][j - 1];
                sum[i][j] += a[i][j];
            }
        }
    }
    
    // 检查(x, y)是否合法
    bool check(int x, int y) {
        return (y <= x + t_n - 1) && (y >= x - t_n + 1) && (y >= -x + t_n - 1) && (y <= -x + (3 * t_n - 3));
    }
    
    int cal_max() {
        int max_value = -1;
        for (int i = 0 ; i < n && i + k - 1 < n ; ++i) {
            for (int j = 0 ; j < n && j + k - 1 < n ; ++j) {
                if (!(check(i, j) && check(i + k - 1, j) && check(i, j + k - 1) && check(i + k - 1, j + k - 1))) continue;
                // 锤子一定要在原来的矩形内
                if (!vis[i][j]) continue;
                int now = sum[i + k - 1][j + k - 1];
                if (i > 0) now -= sum[i - 1][j + k - 1];
                if (j > 0) now -= sum[i + k - 1][j - 1];
                if (i > 0 && j > 0) now += sum[i - 1][j - 1];
                max_value = max(max_value, now);
            }
        }
        return max_value;
    }
    
    void solve() {
        cal_sum();
        printf("%d
    ", cal_max());
    }
    
    int main() {
        read();
        solve();
        return 0;
    }
    
    
  • 相关阅读:
    安全编码1
    VPP tips
    VPP概述汇总
    C语言安全编码摘录
    TCP-proxy
    Scipy Lecture Notes学习笔记(一)Getting started with Python for science 1.4. Matplotlib: plotting
    Scipy Lecture Notes学习笔记(一)Getting started with Python for science 1.3. NumPy: creating and manipulating numerical data
    Scipy Lecture Notes学习笔记(一)Getting started with Python for science 1.2. The Python language
    Scipy Lecture Notes学习笔记(一)Getting started with Python for science 1.1. Python scientific computing ecosystem
    25马5跑道,求最快的五匹马的需要比赛的次数
  • 原文地址:https://www.cnblogs.com/WArobot/p/7884546.html
Copyright © 2011-2022 走看看