zoukankan      html  css  js  c++  java
  • 1222/2516. Kup

    题目描述

    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
    ");
    		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
    ",x1,y1,x2,y2);
    	
    	fclose(stdin);
    	fclose(stdout);
    	
    	return 0;
    }
    
  • 相关阅读:
    241. Different Ways to Add Parentheses java solutions
    89. Gray Code java solutions
    367. Valid Perfect Square java solutions
    46. Permutations java solutions
    116. Populating Next Right Pointers in Each Node java solutions
    153. Find Minimum in Rotated Sorted Array java solutions
    判断两颗树是否相同
    求二叉树叶子节点的个数
    求二叉树第k层的结点个数
    将二叉排序树转换成排序的双向链表
  • 原文地址:https://www.cnblogs.com/gmh77/p/11828845.html
Copyright © 2011-2022 走看看