前缀和与差分

前缀和是数组下标之前(包括此项元素)的所有数组元素之和。
前缀和
一维前缀和
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[i1]+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=0xj=0ya[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[x1][y]+b[x][y1]b[x1][y1]+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 NM1e7,不知道确切范围二维数组存不下,所以用一维数组来存,也可以用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;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chp的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值