码迷,mamicode.com
首页 > 其他好文 > 详细

1222/2516. Kup

时间:2019-11-10 09:57:01      阅读:85      评论:0      收藏:0      [点我收藏+]

标签:scan   cpp   接下来   而且   define   int   long   fclose   print   

题目描述

Description

首先你们得承认今天的题目很短很简洁。。。
然后,你们还得承认接下来这个题目的描述更加简洁!!!
Task:给出一个N*N(1≤N≤2000)的矩阵,还给出一个整数K。要你在给定的矩阵中
求一个子矩阵,这个子矩阵中所有数的和的范围要在[k,2*k] 这个区间。
如果有多个这样的子矩阵,请随便输出一个。

Input

第一行包含两个整数K 和N(1≤K≤10^8,1≤N≤2000)。其意义如题目描述!
接下来有N 行,每行有N 个数,表示题目给出的矩阵。矩阵中的数都是非负数,而且
不大于maxlongint。

Output

输出文件仅包含一行,四个整数,分别是你找出来的矩阵的左上角坐标和右下角坐标。
如果不存在这样的子矩阵,请输出0 0 0 0。

Sample Input

Sample Input1:
4 3
1 1 1
1 9 1
1 1 1


Sample Input2:
8 4
1 2 1 3
25 1 2 1
4 20 3 3
3 30 12 2


Sample Input3:
8 4
12 2 1 3
25 1 2 1
4 20 3 3
3 30 12 2

Sample Output

Sample Output1:
0 0 0 0


Sample Output2:
1 2 2 4


Sample Output3:
1 1 1 1

Data Constraint

Hint

数据约定:
对于30%的数据,1≤N≤5
对于60%的数据,1≤N≤60
对于100%的数据1≤N≤2000

题解

一道神题

首先>2k的数肯定不能选,所以先找一个不包含>2k的数的最大矩阵

用栈可以O(n^2)求出

然后讨论一下

①sum<k

无解

②k<=sum<=2k

当前矩阵即为解

③sum>2k

设当前矩阵中第一行的和为Sum

再讨论一下

1、Sum<k

那么用sum-Sum,不会超过k的边界,所以减掉后继续

2、k<=Sum<=2k

当前行即为解

3、Sum>2k

由于保证了矩阵中没有>2k的数,所以依次把该行中的第一个数删掉

再再讨论一下

设删掉的数大小为a

A、a<k

那么Sum-a不会超过边界,减掉后继续

B、k<=a<=2k

a即为解

C、a>2k

不存在

code

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
using namespace std;

int a[2001][2001];
int f[2001][2001];
long long sum[2001][2001];
int d[2001][2];
int K,K2,n,i,j,k,l,x1,y1,x2,y2,t;
long long mx,Sum;
bool bz;

long long get(int x1,int y1,int x2,int y2)
{
    return sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1];
}

int main()
{
//  freopen("kup.in","r",stdin);
//  freopen("kup.out","w",stdout);
    
    scanf("%d%d",&K,&n);K2=K*2;
    fo(j,1,n) f[0][j]=1;
    fo(i,1,n)
    {
        fo(j,1,n)
        {
            scanf("%d",&a[i][j]);
            
            if (a[i][j]<=K2)
            f[i][j]=f[i-1][j];
            else
            f[i][j]=i+1;
            
            sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
        }
    }
    
    fo(i,1,n)
    {
        t=0;
        fo(j,1,n)
        {
            bz=0;
            while (t && d[t][0]<f[i][j])
            {
                Sum=get(d[t][0],d[t][1],i,j-1);
                if (Sum>mx)
                {
                    mx=Sum;
                    x1=d[t][0];y1=d[t][1];
                    x2=i;y2=j-1;
                }
                
                --t;
                bz=1;
            }
            
            if (f[i][j]<=i && (!t || f[i][j]<d[t][0]))
            {
                ++t;
                d[t][0]=f[i][j];
                if (!bz)
                d[t][1]=j;
            }
        }
        while (t)
        {
            Sum=get(d[t][0],d[t][1],i,n);
            if (Sum>mx)
            {
                mx=Sum;
                x1=d[t][0];y1=d[t][1];
                x2=i;y2=n;
            }
            
            --t;
        }
    }
    
    if (mx<K)
    {
        printf("0 0 0 0\n");
        return 0;
    }
    while (mx>K2)
    {
        Sum=get(x1,y1,x1,y2);
        
        if (Sum>=K)
        {
            x2=x1;
            mx=Sum;
            
            while (mx>K2)
            {
                if (a[x1][y1]<K)
                mx-=a[x1][y1++];
                else
                {
                    mx=a[x1][y1];
                    y2=y1;
                }
            }
        }
        else
        mx-=Sum,++x1;
    }
    
    printf("%d %d %d %d\n",x1,y1,x2,y2);
    
    fclose(stdin);
    fclose(stdout);
    
    return 0;
}

1222/2516. Kup

标签:scan   cpp   接下来   而且   define   int   long   fclose   print   

原文地址:https://www.cnblogs.com/gmh77/p/11828845.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!