差分肯定是都学过,可以用于维护一段区间的连续加
要对上面黄色区域进行连续和,直接暴力肯定会炸啊。
这时候需要用到一个神奇的算法:两个维的差分。
- 维护两个数组
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;
}