前缀和和差分
一维前缀和

1 #include<iostream> 2 using namespace std; 3 4 const int N = 100010; 5 int n,m; 6 int a[N],s[N]; //初始化s[0] = 0 7 8 int main() 9 { 10 scanf("%d%d", &n, &m); 11 for (int i = 1; i <= n; i ++ ) cin >> a[i]; 12 13 for (int i = 1; i <= n; i ++ ) s[i] = s[i - 1] + a[i]; //前缀和读入(公式)初始化 14 15 while (m -- ) // m次读入 16 { 17 int l,r; 18 scanf("%d%d", &l, &r); 19 printf("%d\n",s[r] - s[l - 1]);//部分前缀和 20 } 21 return 0; 22 }
例题:acwing 1230 k倍数=区间问题
时间换空间,且cnt[0] = 1;

1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long LL; 6 7 const int N = 100010; 8 int n,k; 9 LL A[N]; 10 LL s[N],cnt[N];//cnt计算相同余数的序列的个数总和 11 LL res;//计算不相等的余数的个数总和 12 13 int main(){ 14 scanf("%d %d",&n,&k); 15 16 //为什么赋值为1? 17 //因为我们的思路是找两个序列和a%k和b%k的余数相同的个数 18 //而我们的前缀和一般是不包含S0这个东西的,因为没有意义,但是这道题有意义 19 //样例里面前缀和序列%k之后是1 1 0 0 1,两两比较,我们只能找到四个 20 //为什么少了两个?因为我们不一定需要两个序列,单个序列取余=0也构成K倍区间 21 //也就是说s3 s4这两个区间是能单独成K倍区间的,而我们的思路是找两个序列比较 22 //此时,我们就要假设S0=0是有意义的,我们就可以有(s0,s3),(s0,s4)这两个组合 23 cnt[0] = 1; 24 for(int i = 1; i <= n; i ++){ 25 scanf("%lld",&A[i]); 26 s[i] = s[i - 1] + A[i]; 27 s[i] = s[i] % k; 28 res += (cnt[s[i]]); 29 cnt[s[i]] ++;//记录序列%k不同余数的个数 30 //cnt[s[i]]要在res之后做,因为它是记录总数,如果下面再加回去会重复。 31 /*不能写成 32 cnt[s[i]]++; 33 res+=(cnt[s[i]]); 34 */ 35 //用笔写字调试一下就知道了 36 } 37 //cnt[0] = 1; 38 /*for(int i = 1; i <= n; i ++){ 39 /*for(int j = i; j <= n; j ++){ 40 if(s[j] == 0 && j > 0) break; 41 if((s[j] - s[i - 1]) % k == 0){ 42 res ++; 43 } 44 } 45 改成一重循环可以从这里删去。 46 这段代码的含义是: 当j固定时,在1-R之间, 47 找到有多少个L,满足([S[右端点] - S[左端点])%k == 0 48 从含义上优化代码 49 空间换时间 50 */ 51 //res += (cnt[s[i]]); 52 /*我刚开始迷惑为什么不是当cnt[s[i]]>=2的时候才加, 53 现在懂了,因为不一定是两个区间的重叠序列构成K倍区间, 54 一个序列本身如果连续和%k=0也构成K倍区间。故所有的都要加上 55 */ 56 57 /*10^10>10^8 TLE -> 要改为一重循环*/ 58 printf("%lld\n",res); 59 return 0; 60 }
二维前缀和

1 1 #include<iostream> 2 2 using namespace std; 3 3 4 4 const int N = 1010; 5 5 int n,m,q; 6 6 int a[N][N],s[N][N]; 7 7 8 8 int main() 9 9 { 10 10 scanf("%d%d%d", &n, &m,&q); 11 11 for(int i = 1;i <= n; i ++) 12 12 for(int j = 1;j <= m; j ++) 13 13 scanf("%d", &a[i][j]); 14 14 15 15 for(int i = 1; i <= n; i ++) 16 16 for(int j = 1; j <= m ; j ++) 17 17 s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j]; //求前缀和 18 18 19 19 while(q -- ) 20 20 { 21 21 int x1,y1,x2,y2; 22 22 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 23 23 printf("%d\n",s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1]);//算子矩阵的合 24 24 } 25 25 return 0; 26 26 }
S[i,j]S[i,j]即为图1红框中所有数的的和为:
S[i,j]=S[i,j−1]+S[i−1,j]−S[i−1,j−1]+a[i,j]S[i,j]=S[i,j−1]+S[i−1,j]−S[i−1,j−1]+a[i,j]
(x1,y1),(x2,y2)(x1,y1),(x2,y2)这一子矩阵中的所有数之和为:S[x2,y2]−S[x1−1,y2]−S[x2,y1−1]+S[x1−1,
一维差分
1 #include<iostream> 2 using namespace std; 3 4 const int N = 100010; 5 int n,m,q; 6 int a[N],b[N]; 7 8 void insert(int l,int r,int c) 9 { 10 b[l] += c; 11 b[r+ 1 ] -= c; 12 } 13 14 int main() 15 { 16 scanf("%d%d", &n, &m); 17 for(int i = 1; i <= n; i ++) 18 scanf("%d",&a[i]); 19 20 for(int i = 1; i <= n; i ++) insert(i,i,a[i]); //假定a数组是空的,用差分导入a数组 21 22 while (m -- ) 23 { 24 int l,r,c; 25 scanf("%d%d%d",&l, &r, &c); 26 insert(l,r,c); 27 } 28 for(int i = 1; i <= n; i ++) b[i] += b[i - 1]; //前缀和求b数组 29 30 for(int i = 1; i <= n; i ++) printf("%d ",b[i]); 31 return 0; 32 }
二维差分
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int N = 1e3 + 10; 5 int a[N][N], b[N][N]; 6 void insert(int x1, int y1, int x2, int y2, int c) 7 { 8 b[x1][y1] += c; 9 b[x2 + 1][y1] -= c; 10 b[x1][y2 + 1] -= c; 11 b[x2 + 1][y2 + 1] += c; 12 } 13 int main() 14 { 15 int n, m, q; 16 cin >> n >> m >> q; 17 for (int i = 1; i <= n; i++) 18 for (int j = 1; j <= m; j++) 19 cin >> a[i][j]; 20 for (int i = 1; i <= n; i++) 21 { 22 for (int j = 1; j <= m; j++) 23 { 24 insert(i, j, i, j, a[i][j]); //构建差分数组 25 } 26 } 27 while (q--) 28 { 29 int x1, y1, x2, y2, c; 30 cin >> x1 >> y1 >> x2 >> y2 >> c; 31 insert(x1, y1, x2, y2, c); 32 } 33 for (int i = 1; i <= n; i++) 34 { 35 for (int j = 1; j <= m; j++) 36 { 37 b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1]; //二维前缀和 38 } 39 } 40 for (int i = 1; i <= n; i++) 41 { 42 for (int j = 1; j <= m; j++) 43 { 44 printf("%d ", b[i][j]); 45 } 46 printf("\n"); 47 } 48 return 0; 49 }