P3664 [USACO17OPEN]Modern Art 现代艺术 二维差分

例题

差分肯定是都学过,可以用于维护一段区间的连续加

在这里插入图片描述
要对上面黄色区域进行连续和,直接暴力肯定会炸啊。
这时候需要用到一个神奇的算法:两个维的差分。

  • 维护两个数组
    cha1【】【】表示与上一行同一列之间的差分,
    cha2【】【】表示cha1同一行列与列之间的差分
    那么要更新的就是第一个数组的红色部分,这时候你发现红色部分的差分

在这里插入图片描述

在这里插入图片描述
那么cha1变化的就只有蓝色部分

所以只用更新cha2,并且只用更新4个点。x1,y1… x1 ,y1+1…x2,y1…x2,y1+1
但是要注意下面x2是在这个区域加上-1,所以前面应该加上-1,后面是1,反了一下。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1023;
int n,m;
int a[maxn][maxn];
int cha1[maxn][maxn];
int cha2[maxn][maxn];
void add(int x,int y,int need) {
	cha2[x][y]+=need;
}
void dofirst(int x1,int y1,int x2,int y2,int need) {
	add(x1,y1,need);
	add(x1,y2+1,-need);
	add(x2+1,y1,-need); //下面应该反过来,因为下面是加上-1 
	add(x2+1,y2+1,need);
}
void dosecond() {
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=n; j++) {
    cha1[i][j]=cha2[i][j]+cha1[i][j-1];
		}
	}
	for(int j=1; j<=n; j++) {
		for(int i=1; i<=n; i++) {
    a[i][j]=cha1[i][j]+a[i-1][j];
		}
	}
}
void out(int op[][maxn])
{
for(int i=1; i<=n; i++) {
		for(int j=1; j<=n; j++) {
    //cha1[i][j]=cha2[i][j]+cha1[i][j-1];
    cout<<op[i][j]<<" ";
		}
		cout<<endl;
	}
}
int main() {

	cin>>n>>m;
	for(int i=1; i<=m; i++) {
		int x1,y1,x2,y2,q;
		cin>>x1>>y1>>x2>>y2>>q;
		dofirst(x1,y1,x2,y2,q);
	}
	dosecond();
	out(a);
	return 0;
}

题目描述

Art critics worldwide have only recently begun to recognize the
creative genius behind the great bovine painter, Picowso.

Picowso paints in a very particular way. She starts with an N \times
NN×N blank canvas, represented by an N \times NN×N grid of zeros,
where a zero indicates an empty cell of the canvas. She then draws
N^2N 2 rectangles on the canvas, one in each of N^2N 2 colors
(conveniently numbered 1 \ldots N^21…N 2 ). For example, she might
start by painting a rectangle in color 2, giving this intermediate
canvas:

2 2 2 0

2 2 2 0

2 2 2 0

0 0 0 0

She might then paint a rectangle in color 7:

2 2 2 0

2 7 7 7

2 7 7 7

0 0 0 0

And then she might paint a small rectangle in color 3:

2 2 3 0

2 7 3 7

2 7 7 7

0 0 0 0

Each rectangle has sides parallel to the edges of the canvas, and a
rectangle could be as large as the entire canvas or as small as a
single cell. Each color from 1 \ldots N^21…N 2 is used exactly
once, although later colors might completely cover up some of the
earlier colors.

Given the final state of the canvas, please count how many of the N^2N
2 colors could have possibly been the first to be painted.

小TY突然想画画,他有独特的艺术风格,他从N×N空白画布开始,其中0表示画布的空单元格。然后他会在画布上绘制恰好矩形,每个颜色是1到N×N中的一个。他每次可以选择任意一种未使用过的颜色进行绘画。例如,他可以从颜色2的矩形开始,画出这样的画布:

2 2 2 0

2 2 2 0

2 2 2 0

0 0 0 0

然后他可以用颜色7绘制一个矩形:

2 2 2 0

2 7 7 7

2 7 7 7

0 0 0 0

然后他可以在颜色3上绘制一个小矩形:

2 2 3 0

2 7 3 7

2 7 7 7

0 0 0 0

每个矩形都平行于画布边缘,而且矩形可以与整个画布一样大或者像一个单元一样小。每个颜色从1到正好使用一次,后来的颜色可能完全覆盖一些较早画上的颜色。

现在已知画布的最终状态,请计算有多少种颜色可能被第一个被画。

输入格式

The first line of input contains NN, the size of the canvas (1 \leq N
\leq 10001≤N≤1000).

The next NN lines describe the final picture of the canvas, each
containing NN integers that are in the range 0 \ldots N^20…N 2 . The
input is guaranteed to have been drawn as described above, by painting
successive rectangles in different colors.

输出格式

Please output a count of the number of colors that could have been
drawn first.

输入 #1 复制

4 2 2 3 0 2 7 3 7 2 7 7 7 0 0 0 0

输出 #1 复制

14

说明/提示

In this example, color 2 could have been the first to be painted.
Color 3 clearly had to have been painted after color 7, and color 7
clearly had to have been painted after color 2. Since we don’t see the
other colors, we deduce that they also could have been painted first.

首先要找出每一种颜色最上最下最左最右,然后用二维差分去染色,那么这个快快如果至少染的色大于1,那么肯定不选他,也就是说现在这个格子上的颜色肯定不是第一个。
特殊判断一下:当只有一种颜色的时候,上面算法会直接默认为这种颜色也可以
因为不超过1.
但是每个颜色都要食用一次,显然他是最后一个,应该出去一个。除非n==1

  • 假如n!=1&&num_colour==1 ans-=1;
if(co==1&&n!=1)ans--;
#include<bits/stdc++.h>
using namespace std;
const int maxn=1523;
int n,m;
int a[maxn][maxn];
int cha1[maxn][maxn];
int cha2[maxn][maxn];
int num1[maxn*maxn];//记录出现了几种颜色 
int b[maxn][maxn];
int xx1[maxn*maxn],xx2[maxn*maxn],yy1[maxn*maxn],yy2[maxn*maxn];
bool vis[maxn*maxn];
void add(int x,int y,int need) {
	cha2[x][y]+=need;
}
void dofirst(int x1,int y1,int x2,int y2,int need) {
	add(x1,y1,need);
	add(x1,y2+1,-need);
	add(x2+1,y1,-need); //下面应该反过来,因为下面是加上-1
	add(x2+1,y2+1,need);
}
void dosecond() {
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=n; j++) {
			cha1[i][j]+=cha2[i][j]+cha1[i][j-1];
		}
	}
	for(int j=1; j<=n; j++) {
		for(int i=1; i<=n; i++) {
			a[i][j]+=cha1[i][j]+a[i-1][j];
		}
	}
}
void out(int op[][maxn]) {
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=n; j++) {
			//cha1[i][j]=cha2[i][j]+cha1[i][j-1];
			cout<<op[i][j]<<" ";
		}
		cout<<endl;
	}
}
void out1(int x)
{
cout<<"x1="<<xx1[x]<<"x2="<<xx2[x]<<"y1="<<yy1[x]<<"y2="<<yy2[x]<<endl; 
}
int main() {
	cin>>n;
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=n; j++) {
			scanf("%d",&b[i][j]);
			num1[b[i][j]]++;
		}
	}int co=0;
	for(int i=1;i<=n*n;i++)if(num1[i])co++;
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=n; j++) {
			if(!vis[b[i][j]]) {
				vis[b[i][j]]=1;
				xx1[b[i][j]]=i;
			}
			xx2[b[i][j]]=i;
		}
	}
	memset(vis,0,sizeof(vis));
	for(int j=1; j<=n; j++) {
		for(int i=1; i<=n; i++) {
			if(!vis[b[i][j]]) {
				vis[b[i][j]]=1;
				yy1[b[i][j]]=j;
			}
			yy2[b[i][j]]=j;
		}
	}
	for(int i=1;i<=n*n;i++)
	if(xx1[i]!=0&&xx2[i]!=0&&yy1[i]!=0&&yy2[i]!=0)
	dofirst(xx1[i],yy1[i],xx2[i],yy2[i],1);
	//dofirst(1,1,3,2,1);
	dosecond();
//	out(a);
//out1(7);
memset(vis,0,sizeof(vis));
for(int i=1; i<=n; i++) {
		for(int j=1; j<=n; j++) {
		if(a[i][j]!=1)
		vis[b[i][j]]=1;
		}
	}
	int ans=0;
		for(int i=1;i<=n*n;i++)
		if(!vis[i])ans++;
		if(co==1&&n!=1)ans--;
		cout<<ans;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值