前缀和是数组下标之前(包括此项元素)的所有数组元素之和。
前缀和
一维前缀和
b
[
i
]
=
∑
j
=
0
i
a
[
j
]
b[ i ]=\sum_{j=0}^i a[ j ]
b[i]=∑j=0ia[j] ,
b
[
i
]
=
b
[
i
−
1
]
+
a
[
i
]
b[ i ]=b[ i-1 ]+a[ i ]
b[i]=b[i−1]+a[i]
二维前缀和
b
[
x
]
[
y
]
=
∑
i
=
0
x
∑
j
=
0
y
a
[
i
]
[
j
]
b[ x ][ y ]=\sum_{i=0}^x \sum_{j=0}^ya[ i ][ j ]
b[x][y]=i=0∑xj=0∑ya[i][j]
b
[
x
]
[
y
]
=
b
[
x
−
1
]
[
y
]
+
b
[
x
]
[
y
−
1
]
−
b
[
x
−
1
]
[
y
−
1
]
+
a
[
x
]
[
y
]
b[ x ][ y ]=b[ x-1][ y ]+b[ x ][ y-1 ]-b[ x-1 ][ y-1 ]+a[ x ][ y ]
b[x][y]=b[x−1][y]+b[x][y−1]−b[x−1][y−1]+a[x][y]
差分
差分可以看成是前缀和的逆运算
构建差分数组b[ ]
一维差分
b[ L ]+=w;
b[ R+1 ]-=w
二维差分
b[ x1 ][ y1 ]+=w
b[ x2+1 ][ y1]-=w
b[ x1 ][ y2+1]-=w
b[ x2+1][y2+1]+=w
前缀和水题:sum
这道题需要注意的是要将输入数据读完,不能在数据没读完时结束(错了好几次)
而且b[ 0 ]=1。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=5e3+100;
int b[N];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
bool flag=0;
int k=0;
scanf("%d%d",&n,&m);
memset(b,0,sizeof(b));
b[0]=1;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
k=(k+x)%m;
b[k]++;
}
for(int i=0;i<m;i++)
if(b[i]>=2)
{
flag=1;
break;
}
if(flag) printf("YES\n");
else printf("NO\n");
}
return 0;
}
二维差分好题Monitor
题意 : 在一片菜园内装摄像头,摄像头的监控范围是矩形。给出小偷的偷菜也是个矩阵,判断小偷偷菜能否全程被监控。
分析 :这道题比较好的一点是用一维数组来代替二维数组,因为
N
∗
M
≤
1
e
7
N*M \leq 1e7
N∗M≤1e7,不知道确切范围二维数组存不下,所以用一维数组来存,也可以用vector存。这道题的解法是用二维差分先来确定监控范围,再对二维差分数组求两次前缀和,得到原数组的前缀和数组。最后判断小偷偷的矩阵面积,是否等于监控在此区域的面积即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e7+100;
int p,q;
int a[N];
int n,m;
void add(int x,int y,int w)
{
if(x>n||y>m)//监控范围超过菜园不在n*m范围内
return ;
a[(x-1)*m+y]+=w;
}
int query(int x,int y)
{
if(x==0||y==0)
return 0;
return a[(x-1)*m+y];
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(a,0,sizeof(a));
scanf("%d",&p);
int x1,x2,y1,y2;
for(int i=0;i<p;i++)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
add(x1,y1,1);
add(x2+1,y1,-1);
add(x1,y2+1,-1);
add(x2+1,y2+1,1);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[(i-1)*m+j]=query(i,j-1)+query(i-1,j)-query(i-1,j-1)+a[(i-1)*m+j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[(i-1)*m+j]!=0)
a[(i-1)*m+j]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[(i-1)*m+j]=query(i,j-1)+query(i-1,j)-query(i-1,j-1)+a[(i-1)*m+j];
scanf("%d",&q);
while(q--)
{
int x1,x2,y1,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
int sum=query(x2,y2)-query(x1-1,y2)-query(x2,y1-1)+query(x1-1,y1-1);
// printf("sum %d\n",sum);
if(sum==(x2-x1+1)*(y2-y1+1))
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}