题目描述
淘淘有一块长方形的
n
×
m
n \times m
n×m 大小的农田,农田的每一格上种着一种植物,在第
i
i
i 行,第
j
j
j 列的植物是第
a
[
i
]
[
j
]
a[i][j]
a[i][j] 种。
热心的蓝蓝想帮淘淘施肥,但是第
i
i
i 种肥料只能对第
i
i
i 种植物起作用,如果第
i
i
i 种肥料施在第
j
j
j 种植物上且
i
≠
j
i \neq j
i=j,这一株植物就会死。现在蓝蓝施肥了
T
T
T 次,第
i
i
i 次施肥会把第
k
[
i
]
k[i]
k[i] 种肥料给矩阵
[
x
1
[
i
]
.
.
.
x
2
[
i
]
]
[
y
1
[
i
]
.
.
.
y
2
[
i
]
]
[x1[i]...x2[i]][y1[i]...y2[i]]
[x1[i]...x2[i]][y1[i]...y2[i]] 中的所有植物。
淘淘看到自己有植物死了,十分伤心,你要求出有多少植物死了。
输入格式
第一行三个整数
n
,
m
n,m
n,m 和
T
T
T。
接下来
n
n
n 行每行
m
m
m 个整数,第
i
i
i 行第
j
j
j 个整数表示
a
[
i
]
[
j
]
a[i][j]
a[i][j]。
接下来
T
T
T 行每行五个整数,
x
1
[
i
]
,
y
1
[
i
]
,
x
2
[
i
]
,
y
2
[
i
]
,
k
[
i
]
x1[i], y1[i], x2[i], y2[i], k[i]
x1[i],y1[i],x2[i],y2[i],k[i],表示一次施肥。
输出格式
一行一个整数表示有多少植物死了。
样例输入
2 2 2
1 2
2 3
1 1 2 2 2
2 1 2 1 1
样例输出
3
数据范围与提示
对于
100
%
100\%
100% 的数据,满足
1
≤
n
×
m
≤
1000000
,
1
≤
T
≤
1000000
,
1
≤
a
[
i
]
[
j
]
,
k
[
i
]
≤
n
×
m
,
1
≤
x
1
[
i
]
≤
x
2
[
i
]
≤
n
,
1
≤
y
1
[
i
]
≤
y
2
[
i
]
≤
m
1 \leq n \times m \leq 1000000,1 \leq T \leq 1000000,1 \leq a[i][j], k[i] \leq n \times m,1 \leq x1[i] \leq x2[i] \leq n,1 \leq y1[i] \leq y2[i] \leq m
1≤n×m≤1000000,1≤T≤1000000,1≤a[i][j],k[i]≤n×m,1≤x1[i]≤x2[i]≤n,1≤y1[i]≤y2[i]≤m。
S
u
b
t
a
s
k
1
(
30
p
t
s
)
Subtask\ 1(30pts)
Subtask 1(30pts) : 保证
1
≤
n
×
m
×
T
≤
1
0
7
1 \leq n \times m \times T \leq 10^7
1≤n×m×T≤107。
S
u
b
t
a
s
k
2
(
40
p
t
s
)
Subtask\ 2(40pts)
Subtask 2(40pts) : 满足
1
≤
a
[
i
]
[
j
]
,
k
[
i
]
≤
2
1 \leq a[i][j], k[i] \leq 2
1≤a[i][j],k[i]≤2。
S
u
b
t
a
s
k
3
(
30
p
t
s
)
Subtask\ 3(30pts)
Subtask 3(30pts) : 无任何其他限制。
题解
首先oj上数据太水,直接暴力竟然可以70分……
看到对一个矩阵施肥,不难想到二维前缀和。考场上想不到暴力分那么多,对于
S
u
b
t
a
s
k
2
Subtask\ 2
Subtask 2大都会对两种类型分别进行前缀和统计,可以算出每种植物被施肥的次数(其实只要知道有没有被施肥就可以)。
对付多种类型,这里用到的是拆位思想。
我们把肥料看作对每一个二进制位施0或1的肥。要想一种植物不死,这种植物为1的二进制位上不能被施0的肥,为0的二进制位上不能被施1的肥,每一位分开做即可。
这个思路显然是正确的,但我的经历充分证明了思路正确离代码AC还有十万八千里……
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
map < int,map<int,int > > tp,flg;
map < int,map<int,map<int,map<int,int> > > > c,qzh;
int n,m,t,ans,xi,yi,xj,yj,k,mxk;
int main(){
scanf("%d%d%d",&n,&m,&t);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&tp[i][j]);
}
}
for(int i=1;i<=t;i++){
scanf("%d%d%d%d%d",&xi,&yi,&xj,&yj,&k);
mxk=max(mxk,k);
for(int j=0;(1<<j)<=k;j++){
if((1<<j)&k){
c[xi][yi][j][1]++;
c[xj+1][yj+1][j][1]++;
c[xi][yj+1][j][1]--;
c[xj+1][yi][j][1]--;
continue;
}
c[xi][yi][j][0]++;
c[xj+1][yj+1][j][0]++;
c[xi][yj+1][j][0]--;
c[xj+1][yi][j][0]--;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int q=0;(1<<q)<=mxk;q++){
qzh[i][j][q][0]=qzh[i][j-1][q][0]+qzh[i-1][j][q][0]-qzh[i-1][j-1][q][0]+c[i][j][q][0];
qzh[i][j][q][1]=qzh[i][j-1][q][1]+qzh[i-1][j][q][1]-qzh[i-1][j-1][q][1]+c[i][j][q][1];
int cc=1<<q;
if(flg[i][j]==0&&((qzh[i][j][q][1]>0&&(tp[i][j]&cc)==0)||(qzh[i][j][q][0]>0&&(tp[i][j]&cc)>0))){
flg[i][j]=1;
ans++;
}
}
}
}
printf("%lld\n",ans);
return 0;
}
这是我一开始的代码,蒟蒻的我对于不定长的数据范围居然想用map,顺理成章地T……后来改用vector,当然,大同小异
我百度了一会发现下面这种方法或许能用了,于是:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int n,m,t,ans,xi,yi,xj,yj,k,mxk;
int main(){
scanf("%d%d%d",&n,&m,&t);
int tp[n+10][m+10],flg[n+10][m+10],c[n+10][m+10][21][2],qzh[n+10][m+10][21][2];
memset(flg,0,sizeof(flg));
memset(c,0,sizeof(c));
memset(qzh,0,sizeof(qzh));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&tp[i][j]);
}
}
for(int i=1;i<=t;i++){
scanf("%d%d%d%d%d",&xi,&yi,&xj,&yj,&k);
mxk=max(mxk,k);
for(int j=0;j<=20;j++){
if(((1<<j)&k)>0){
c[xi][yi][j][1]++;
c[xj+1][yj+1][j][1]++;
c[xi][yj+1][j][1]--;
c[xj+1][yi][j][1]--;
continue;
}
c[xi][yi][j][0]++;
c[xj+1][yj+1][j][0]++;
c[xi][yj+1][j][0]--;
c[xj+1][yi][j][0]--;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int q=0;q<=20;q++){
qzh[i][j][q][0]=qzh[i][j-1][q][0]+qzh[i-1][j][q][0]-qzh[i-1][j-1][q][0]+c[i][j][q][0];
qzh[i][j][q][1]=qzh[i][j-1][q][1]+qzh[i-1][j][q][1]-qzh[i-1][j-1][q][1]+c[i][j][q][1];
int cc=1<<q;
if(flg[i][j]==0&&((qzh[i][j][q][1]>0&&(tp[i][j]&cc)==0)||(qzh[i][j][q][0]>0&&(tp[i][j]&cc)>0))){
flg[i][j]=1;
ans++;
}
}
}
}
printf("%d\n",ans);
return 0;
}
RE
于是我把二维数据折叠到一维数组:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define pos(x, y) ((x) * (m + 2) + y)
using namespace std;
int n,m,t,ans,xi,yi,xj,yj,k,mxk;
int tp[4000000],flg[4000000],c[4000000][21][2],qzh[4000000][21][2];
int main(){
//freopen("farm.in","r",stdin);
//freopen("farm.out","w",stdout);
scanf("%d%d%d",&n,&m,&t);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&tp[pos(i,j)]);
}
}
for(int i=1;i<=t;i++){
scanf("%d%d%d%d%d",&xi,&yi,&xj,&yj,&k);
mxk=max(mxk,k);
for(int j=0;j<=20;j++){
if(((1<<j)&k)>0){
c[pos(xi,yi)][j][1]++;
c[pos(xj+1,yj+1)][j][1]++;
c[pos(xi,yj+1)][j][1]--;
c[pos(xj+1,yi)][j][1]--;
continue;
}
c[pos(xi,yi)][j][0]++;
c[pos(xj+1,yj+1)][j][0]++;
c[pos(xi,yj+1)][j][0]--;
c[pos(xj+1,yi)][j][0]--;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int q=0;q<=20;q++){
qzh[pos(i,j)][q][0]=qzh[pos(i,j-1)][q][0]+qzh[pos(i-1,j)][q][0]-qzh[pos(i-1,j-1)][q][0]+c[pos(i,j)][q][0];
qzh[pos(i,j)][q][1]=qzh[pos(i,j-1)][q][1]+qzh[pos(i-1,j)][q][1]-qzh[pos(i-1,j-1)][q][1]+c[pos(i,j)][q][1];
int cc=1<<q;
if(flg[pos(i,j)]==0&&((qzh[pos(i,j)][q][1]>0&&(tp[pos(i,j)]&cc)==0)||(qzh[pos(i,j)][q][0]>0&&(tp[pos(i,j)]&cc)>0))){
flg[pos(i,j)]=1;
ans++;
}
}
}
}
printf("%d\n",ans);
return 0;
}
MLE
最后把遍历每一位的循环放到最外面,可以优化掉一维:(AC代码)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define pos(x, y) ((x) * (m + 2) + y)
using namespace std;
int n,m,t,ans,xi,yi,xj,yj,k,mxk;
int tp[4000000],cw[4000000],c[4000000][2];
bool flag[4000000];
struct query{
int xi,yi,xj,yj,k;
}Q[1000005];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
int main(){
n=read();m=read();t=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
tp[pos(i,j)]=read();
for(int i=1;i<=t;i++){
Q[i].xi=read();
Q[i].yi=read();
Q[i].xj=read();
Q[i].yj=read();
Q[i].k=read();
}
for(int kk=0;kk<20;kk++){
for(int i=0;i<=n+1;i++)
for(int j=0;j<=m+1;j++)
c[pos(i,j)][0]=c[pos(i,j)][1]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cw[pos(i,j)]=(tp[pos(i,j)]>>kk) & 1;
for(int i=1;i<=t;i++){
int tt=Q[i].k & 1;
Q[i].k>>=1;
c[pos(Q[i].xi,Q[i].yi)][tt]++;
c[pos(Q[i].xj+1,Q[i].yj+1)][tt]++;
c[pos(Q[i].xi,Q[i].yj+1)][tt]--;
c[pos(Q[i].xj+1,Q[i].yi)][tt]--;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
c[pos(i,j)][0]+=c[pos(i,j-1)][0]+c[pos(i-1,j)][0]-c[pos(i-1,j-1)][0];
c[pos(i,j)][1]+=c[pos(i,j-1)][1]+c[pos(i-1,j)][1]-c[pos(i-1,j-1)][1];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(c[pos(i,j)][cw[pos(i,j)]^1])
flag[pos(i,j)]=true;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(flag[pos(i,j)]) ans++;
printf("%d\n",ans);
return 0;
}