DAY 2 前缀和&差分

容斥原理:

 前缀和:
 一维 sum[i]=sun[i-1]+a[i]
 二维 sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]
     
 差分:
 a[i]=sum[i]-sum[i-1]
 a[i][j]=sum[i][j]-sum[i-1][j]-sum[i][j-1]+sum[i-1][j-1]
 ​
 求[l,r]的和
 ans=sum[r]-sum[l-1]
 ​
 求a[x1][y1]到a[x2][y2]的和
 ans=sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1]
 差分标记数组:(解决元素变化)
 l,r,q : 把[l,r]的元素都加上q
 ​
 一维:
 int b[105];
 int sum[b];
 while(m>0){
     cin>>l>>r>>q;
     b[l]+=q;
     b[l+1]-=q;  
 }
 for(int i=1,i<=n,i++){
     sumb[i]=sum[i-1]+b[i];
     cout<<a[i]+sumb[i];
 }

[深进1.例1]求区间和

题目描述

给定 n 个正整数组成的数列 a_1, a_2, \cdots, a_n 和 m 个区间 [l_i,r_i],分别求这 m 个区间的区间和。

输入格式

第一行,为一个正整数 n 。

第二行,为 n 个正整数 a_1,a_2, \cdots ,a_n

第三行,为一个正整数 m 。

接下来 m 行,每行为两个正整数 l_i,r_i ,满足 1\le l_i\le r_i\le n

输出格式

共 m 行。

第 i 行为第 i 组答案的询问。

样例 #1

样例输入 #1

 4
 4 3 2 1
 2
 1 4
 2 3

样例输出 #1

 10
 5

提示

样例解释:第 1 到第 4 个数加起来和为 10。第 2 个数到第 3 个数加起来和为 5。

对于 50% 的数据:n,m\le 1000 ;

对于 100% 的数据:1 \leq n,m\le 10^5,1 \leq a_i\le 10^4。

 #include <string>       
 #include <iostream>   
 #include <algorithm>
 #include <vector>
 using namespace std;
 ​
 int n,m,l,r;
 int a[100005];
 int sum[100005];
 int main()
 {
     cin>>n;
     for(int i=1;i<=n;i++){
         cin>>a[i];
         sum[i]=sum[i-1]+a[i];
         }
     cin>>m;
     for(int i=1;i<=m;i++){
         cin>>l>>r;
         cout<<sum[r]-sum[l-1]<<endl;
     }   
 return 0;
 }

最大正方形

题目描述

在一个 n\times m 的只包含 0 和 1 的矩阵里找出一个不包含 0 的最大正方形,输出边长。

输入格式

输入文件第一行为两个整数 n,m(1\leq n,m\leq 100),接下来 n 行,每行 m 个数字,用空格隔开,0 或 1。

输出格式

一个整数,最大正方形的边长。

样例 #1

样例输入 #1

 4 4
 0 1 1 1
 1 1 1 0
 0 1 1 0
 1 1 0 1

样例输出 #1

 2

 #include <iostream>   
 #include <algorithm>
 using namespace std;
 ​
 int n, m;
 int a[105][105];
 int b[105][105];//前缀和数组
 int ans;//最大的边长
 int flag;
 int l;//边长
 int s;//面积
 ​
 int main()
 {
     cin >> n>>m;
     for (int i = 1; i <= n; i++)
     {
         for (int j = 1; j <= m; j++)
         {
             cin >> a[i][j];
             if (a[i][j] == 1) {
                 flag = 1;
             }
             b[i][j] = b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1] + a[i][j];
         }
     }
     if (flag == 0)
     {
         cout << 0 << endl;
     }
     else {
         ans = 1;
         l = 2;
         while (l <= min(n, m))//枚举边长
         {
             for (int i = l; i <= n; i++)
             {
                 for (int j = l; j <= m; j++)//枚举正方形右下角的坐标
                 {
                     s= b[i][j] - b[i - l][j] - b[i][j - l] + b[i - l][j - l];
                     if (s == l * l)
                     {
                         ans = max(ans, l);
                     }
                 }
             }
             l++;
         }
     }
     cout << ans << endl;
     return 0;
 }

地毯

题目描述

在 n\times n 的格子上有 m 个地毯。

给出这些地毯的信息,问每个点被多少个地毯覆盖。

输入格式

第一行,两个正整数 n,m。意义如题所述。

接下来 m 行,每行两个坐标 (x_1,y_1) 和 (x_2,y_2),代表一块地毯,左上角是 (x_1,y_1),右下角是 (x_2,y_2)。

输出格式

输出 n 行,每行 n 个正整数。

第 i 行第 j 列的正整数表示 (i,j) 这个格子被多少个地毯覆盖。

样例 #1

样例输入 #1

 5 3
 2 2 3 3
 3 3 5 5
 1 2 1 4

样例输出 #1

 0 1 1 1 0
 0 1 1 0 0
 0 1 2 1 1
 0 0 1 1 1
 0 0 1 1 1

提示

样例解释

覆盖第一个地毯后:

00000
01100
01100
00000
00000

覆盖第一、二个地毯后:

00000
01100
01211
00111
00111

覆盖所有地毯后:

01110
01100
01211
00111
00111

数据范围

对于 20\% 的数据,有 n\le 50,m\le 100。

对于 100\% 的数据,有 n,m\le 1000。

 #include <iostream>   
 #include <algorithm>
 #include <vector>
 ​
 using namespace std;
 //二维差分标记数组
 int n,m;
 int b[1005][1005];//差分标记数组
 int sumb[1005][1005];//前缀和数组
 int x1,y1,x2,y2;
 int main()
 {
     cin>>n>>m;
     for(int i=1;i<=m;i++){
         cin>>x1>>y1>>x2>>y2;
         b[x1][y1]+=1;
         b[x1][y2+1]-=1;
         b[x2+1][y1]-=1;
         b[x2+1][y2+1]+=1;
         }
     for (int i = 1; i <= n; i++) {
         for (int j = 1; j <= n; j++) {
             sumb[i][j] = sumb[i - 1][j] + sumb[i][j - 1] - sumb[i - 1][j - 1] + b[i][j];
             cout<<sumb[i][j]<<" ";
         }
         cout<<endl;
     }
     return 0;
 }

  • 38
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值