容斥原理:
前缀和: 一维 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
提示
样例解释
覆盖第一个地毯后:
0 | 0 | 0 | 0 | 0 |
---|---|---|---|---|
0 | 1 | 1 | 0 | 0 |
0 | 1 | 1 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
覆盖第一、二个地毯后:
0 | 0 | 0 | 0 | 0 |
---|---|---|---|---|
0 | 1 | 1 | 0 | 0 |
0 | 1 | 2 | 1 | 1 |
0 | 0 | 1 | 1 | 1 |
0 | 0 | 1 | 1 | 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 |
数据范围
对于 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; }