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;
    }
    
    
  • 相关阅读:
    mysql 重置root 账户密码
    Applicationpoolidentity 好有趣哦
    类模板的困扰 LNK2019 (转)
    C++中定义比较函数的三种方法
    Spring的AOP,Struts2的拦截器(Interceptor),以及springMVC的(interceptor)
    MyBatis与Hibernate总结篇
    Java中的回调
    闲来重写一下快速排序
    【lucene】一个简单的招聘网站的建立
    【Lucene】小谈lucene的BooleanQuery查询对象
  • 原文地址:https://www.cnblogs.com/WArobot/p/7884546.html
Copyright © 2011-2022 走看看