• AcWing1683 刷谷仓题解


    题目传送门

    题面简述

    在坐标系的第一象限中画(n)个矩阵(每个矩阵的边与坐标系平行),问有多少面积被恰好(k)个矩阵覆盖

    (40pts)思路简述

    由于矩阵右上角最多到((1000,1000)),所以可以直接建一个(1000 imes1000)的数组模拟

    (40pts)代码

    代码很易懂就不放注释了

    #include<iostream>
    using namespace std;
    int map[1005][1005];
    int main()
    {
    	int n,k;
    	int cnt=0;
    	cin>>n>>k;
    	for(int i=0;i<n;i++)
    	{
    		int x1,y1,x2,y2;
    		cin>>x1>>y1>>x2>>y2;
    		for(int x=x1;x<x2;x++)
    			for(int y=y1;y<y2;y++)
    				map[x][y]++;
    	}
    	for(int i=1;i<=1000;i++)
    		for(int j=1;j<=1000;j++)
    			if(map[i][j]==k)
    				cnt++;
    	cout<<cnt;
    	return 0;
    }
    

    正文开始

    (100pts)思路简述

    有没有用几个数字来表示数组中被覆盖矩阵个数的方式

    当然有了

    用前缀和啊

    我们要牵一发而动全身,以点代面

    在做前缀和相关的题目时,我们关注的都是怎么计算出某一段的和

    而这题我们可以换个角度来想

    我们将(x1)设为(2),将(y1)设为(2),将(x2)设为(5),将(y2)设为(4)

    众所周知

    在二维前缀和中,一旦(a_{2,2})增加一,(f_{2,2})(f_{3,2})(f_{2,3})一直到(f_{infty,infty})都会增加一

    不会吧,不会吧,不会还有人不知道a是原数组而f是前缀和数组吧

    在上句中,(a_{2,2})增加一就可以看作在((2,2))((infty,infty))画了一个矩阵(在(f)数组中)

    而我们要画的并不是一个((x1,y1))((infty,infty))的矩阵

    怎么剪掉多余部分呢?

    直接减不就完了

    反过来(指“众所周知”后一句),一旦(a_{5,2})减少一,(f_{5,2})一直到(f_{infty,infty})也都会减少一

    在上句中,(a_{4,2})减少一就可以看作在((5,2))((infty,infty))抹掉了一个矩阵(在(f)数组中)

    而在(a_{2,4})减少一就可以看作在((2,4))((infty,infty))抹掉了一个矩阵(在(f)数组中)

    那么这个时候,聪明的小朋友就会发现了,在((5,4))((infty,infty))多抹去了一个矩阵!

    我们在(a_{5,4})增加一就能把这个多减的矩阵补回来

    我们只用改动4个变量就能表示出一层被覆盖的矩阵


    用题目中给出的量顺一下:

    要想在加载前缀和数组时加载出矩阵的覆盖情况,我们可以改动四个位置

    ((x1,y1))(加一)、((x1,y2))(减一)、((x2,y1))(减一)和((x2,y2))(加一)

    (a_{x1,y1})加一得到((x1,y1))((infty,infty))的大矩阵

    (a_{x1,y2})(a_{x2,y1})减一的目的是减去大矩阵多余的部分,但会多减

    (a_{x2,y2})加一补上了多减的部分

    按照这种方法加载出存储着所有矩阵覆盖信息的(a)数组,再加载出(f)前缀和数组,顺便在加载时计算出覆盖了(k)层的面积

    (100pts)代码

    #include<iostream>
    using namespace std;
    long long a[1005][1005];//为了省空间将“f”数组与“a”数组合二为一
    int main()
    {
    	int n,k;
    	int cnt=0;
    	cin>>n>>k;
    	for(int i=0;i<n;i++)
    	{
    		int x1,y1,x2,y2;
    		cin>>x1>>y1>>x2>>y2;
    		a[x1][y1]++;
    		a[x1][y2]--;
    		a[x2][y1]--;
    		a[x2][y2]++;//将矩阵存入数组
    	}
    	for(int i=0;i<=1000;i++)
    		for(int j=0;j<=1000;j++)
    		{
    			if(!i&&!j)
    				continue;
    			if(!i)
    				a[i][j]+=a[i][j-1];
    			else if(!j)
    				a[i][j]+=a[i-1][j];//以上六行均为判断边界
    			else
    				a[i][j]+=a[i][j-1]+a[i-1][j]-a[i-1][j-1];
    			if(a[i][j]==k)
    				cnt++;//判断正好覆盖k层的面积
    		}
    	cout<<cnt;
    	return 0;
    }
    

    都看到这里了,不留下个赞么

    死皮赖脸.jpg

    我要拿金牌!
  • 相关阅读:
    设计模式之策略模式
    assert断言——调试中不应该是syso
    Spring AOP
    MyBatis
    事务处理与使用连接池管理连接
    管理结果集(ResultSet)
    执行SQL语句的方式
    JDBC基础:
    NIO.2
    NIO
  • 原文地址:https://www.cnblogs.com/jerrywang-blogs/p/14900407.html
Copyright © 2020-2023  润新知