zoukankan      html  css  js  c++  java
  • 洛谷P3474 KUP-Plot purchase

    简要题意:

    给你一个n * n的非负矩阵,求问是否有子矩阵满足和在[k, 2k]之间。若有输出方案。n<=2000。

    解:

    首先n4暴力很好想(废话),然后发现可以优化成n3log2n,但是还是过不了.....

    正解十分之玄妙.....

    首先所有大于2k的都不可用。

    然后若有一个子矩阵的和不小于k,那么一定有解,且解是这个矩阵的一个子矩阵。

    证:

    当这个矩阵的和大于2k时,切这个矩阵。

    一定有一块大于k。

    然后就这样了......

    具体实现就看代码了。

      1 #include <cstdio>
      2 #include <algorithm>
      3 
      4 typedef long long LL;
      5 const int N = 2010;
      6 const LL INF = (1ll << 63) - 1;
      7 
      8 LL G[N][N], sum[N][N];
      9 int h[N][N], l[N], r[N], p[N], top;
     10 
     11 inline LL getsum(int left, int right, int u, int d) {
     12     return sum[d][right] - sum[d][left - 1] - sum[u - 1][right] + sum[u - 1][left - 1];
     13 }
     14 
     15 int main() {
     16 
     17     int n, m;
     18     LL k;
     19     scanf("%lld%d", &k, &n);
     20     m = n;
     21     for(int i = 1; i <= n; i++) {
     22         for(int j = 1; j <= m; j++) {
     23             scanf("%lld", &G[i][j]);
     24             sum[i][j] = sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1] + G[i][j];
     25         }
     26     }
     27     
     28     for(int j = 1; j <= m; j++) {
     29         for(int i = 1; i <= n; i++) {
     30             if(G[i][j] > (k << 1)) {
     31                 h[i][j] = 0;
     32             }
     33             else {
     34                 h[i][j] = h[i - 1][j] + 1;
     35             }
     36             //printf("h %d %d %d 
    ", i, j, h[i][j]);
     37         }
     38     }
     39     
     40     LL large = -INF;
     41     int u, d, left, right;
     42     
     43     for(int i = 1; i <= n; i++) { // down 
     44         top = 0;
     45         p[0] = 0;
     46         for(int j = 1; j <= m; j++) {
     47             while(top && h[i][p[top]] >= h[i][j]) {
     48                 top--;
     49             }
     50             l[j] = p[top] + 1;
     51             p[++top] = j;
     52         }
     53         top = 0;
     54         p[0] = m + 1;
     55         for(int j = m; j >= 1; j--) {
     56             while(top && h[i][p[top]] >= h[i][j]) {
     57                 top--;
     58             }
     59             r[j] = p[top] - 1;
     60             p[++top] = j;
     61         }
     62         
     63         for(int j = 1; j <= m; j++) {
     64             LL t = getsum(l[j], r[j], i - h[i][j] + 1, i);
     65             if(t > large) {
     66                 large = t;
     67                 u = i - h[i][j] + 1;
     68                 d = i;
     69                 left = l[j];
     70                 right = r[j];
     71             }
     72         }
     73     }
     74     
     75     if(large < k) {
     76         printf("NIE");
     77         return 0;
     78     }
     79     
     80     
     81     while(large > (k << 1)) {
     82         if(u < d) {
     83             int mid = (u + d) >> 1;
     84             if(getsum(left, right, u, mid) >= k) {
     85                 d = mid;
     86             }
     87             else {
     88                 u = mid + 1;
     89             }
     90         }
     91         else {
     92             int mid = (left + right) >> 1;
     93             if(getsum(left, mid, u, d) >= k) {
     94                 right = mid;
     95             }
     96             else {
     97                 left = mid + 1;
     98             }
     99         }
    100         large = getsum(left, right, u, d);
    101     }
    102     
    103     printf("%d %d %d %d", left, u, right, d);
    104     
    105     return 0;
    106 }
    AC代码
  • 相关阅读:
    【LeetCode-位运算】位1的个数
    【LeetCode-数组】调整数组顺序使奇数位于偶数前面
    mySQL数据库中.frm和.myi和.myd和.ibd文件是什么文件?
    安装docker-compose的两种方式
    将第三方jar包 安装到 maven仓库
    limit分页查询
    pom.xml配置指定仓库
    linux常用命令
    正则笔记
    使用conda创建虚拟环境
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/9812561.html
Copyright © 2011-2022 走看看