前缀和 和 差分
前缀和
定义
前缀和可以简单理解为「数列的前 n 项的和」,是一种重要的预处理方式,能大大降低查询的时间复杂度。
一维前缀和
P5638 【CSGRound2】光骓者的荣耀
1 #include <iostream> 2 #include<cmath> 3 using namespace std; 4 const int N=1000010; 5 int n,k; 6 long long a,b[N],mmax=0; 7 int main() { 8 cin>>n>>k; 9 for(int i=1; i<n; i++) { 10 cin>>a; 11 b[i]=b[i-1]+a; 12 if(i>=k) { 13 mmax=max(mmax,b[i]-b[i-k]); 14 } else { 15 mmax=max(mmax,b[i]); 16 } 17 //cout<<"i="<<i<<endl; 18 } 19 cout<<b[n-1]-mmax; 20 return 0; 21 }
P1115 最大子段和
1 #include<iostream> 2 #include<cmath> 3 using namespace std; 4 const int N=2*100010; 5 int n,a;//保存原数列 6 long long b[N]; //保存a的前缀和 7 int main() { 8 scanf("%d",&n); 9 for(int i=1; i<=n; i++) { 10 scanf("%d",&a); 11 b[i]=a+b[i-1]; 12 } 13 long long ans=b[1];//定义答案初始值 14 long long mmin=0;//定义前n项和最小值 15 for(int i=1; i<=n; i++) { 16 ans=max(ans,b[i]-mmin);//连续区间至少要有一个数 17 mmin=min(mmin,b[i]); 18 } 19 printf("%lld",ans); 20 return 0; 21 }
P1865 A % B Problem
1 //P1865 A % B Problem 2 #include<bits/stdc++.h> 3 using namespace std; 4 int l,r,n,m; 5 int a[1000010]; 6 7 bool is_prime(int x) { 8 if(x<=1) return false; 9 for(int i=2; i*i<=x; i++) { 10 if(x%i==0) return false; 11 } 12 return true; 13 } 14 15 void work(int y) { 16 for(int i=1; i<=y; i++) { 17 if(is_prime(i)) a[i]++; 18 a[i]+=a[i-1]; 19 //cout<<"***"<<a[i]<<endl; 20 } 21 return; 22 } 23 24 int main() { 25 cin>>n>>m; 26 work(m); 27 for(int i=1; i<=n; i++) { 28 cin>>l>>r; 29 int t=a[r]-a[l-1]; 30 if(l<1||r>m) 31 cout<<"Crossing the line\n"; 32 else 33 cout<<a[r]-a[l-1]<<"\n"; 34 } 35 return 0; 36 }
二维前缀和
P1719 最大加权矩形
1 #include<iostream> 2 #include<cmath> 3 using namespace std; 4 const int N=130; 5 int a,s[N][N]; 6 int n; 7 int main() { 8 cin>>n; 9 for(int i=1; i<=n; i++) { 10 for(int j=1; j<=n; j++) { 11 cin>>a; 12 s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a; 13 } 14 } 15 int ans=s[1][1]; 16 for(int i=1; i<=n; i++) { 17 for(int j=1; j<=n; j++) { 18 for(int a=1; a<=i; a++) { 19 for(int b=1; b<=j; b++) { 20 int t=s[i][j]-s[i][b-1]-s[a-1][j]+s[a-1][b-1]; 21 ans=max(ans,t); 22 } 23 } 24 25 } 26 } 27 cout<<ans; 28 return 0; 29 }
P2004 领地选择
1 #include <iostream>
2 #include<cmath>
3 using namespace std;
4 const int N=1010;
5 int n,m,c;
6 int a,b[N][N];
7 int main() {
8 cin>>n>>m>>c;
9 for(int i=1; i<=n; i++) {
10 for(int j=1; j<=m; j++) {
11 cin>>a;
12 b[i][j]=b[i-1][j]+b[i][j-1]-b[i-1][j-1]+a;
13 }
14 }
15 int ans=b[c][c];
16 int mi=1,mj=1;
17 for(int i=1; i+c-1<=n; i++) { //首都左上角的位置
18 for(int j=1; j+c-1<=m; j++) {
19 int x1=i,y1=j,x2=x1+c-1,y2=y1+c-1;
20 int t=b[x2][y2]-b[x2][y1-1]-b[x1-1][y2]+b[x1-1][y1-1];
21 if(t>ans) {
22 ans=t;
23 mi=i;
24 mj=j;
25 }
26 //cout<<i<<' '<<j<<" "<<b[i][j]<<' '<<x2<<' '<<y2<<" "<<b[x2][y2]<<" "<<t<<endl;
27 }
28 }
29 cout<<mi<<' '<<mj<<endl;
30 return 0;
31 }
一维差分
P3406 海底高铁
1 #include <iostream> 2 #include<cmath> 3 using namespace std; 4 const int N=100010; 5 long long n,m; 6 long long p[N],a[N],b[N],c[N]; 7 long long v[N]; 8 int main() { 9 cin>>n>>m; 10 for(int i=1; i<=m; i++) { 11 cin>>p[i]; 12 } 13 for(int i=1; i<n; i++) { 14 cin>>a[i]>>b[i]>>c[i]; 15 } 16 //需要求出每个城市经过了多少次 17 for(int i=1; i<m; i++) { 18 int l=min(p[i],p[i+1]); 19 int r=max(p[i],p[i+1]); 20 v[l]++; 21 v[r]--; 22 } 23 long long ans=0; 24 for(int i=1; i<=n; i++) { 25 v[i]+=v[i-1];//求出访问过每个城市几次 26 ans+=min(a[i]*v[i],b[i]*v[i]+c[i]); 27 } 28 cout<<ans<<endl; 29 return 0; 30 }
T319771 植树节(planting)山东CSP-J2022 入门组1
1 //差分 2 #include<iostream> 3 #include<cmath> 4 using namespace std; 5 const int N=1000010; 6 int n,l,r,mmin=N,mmax=0; 7 int a;//记录真正的浇水次数 8 int b[N];//差分数组 9 10 void insert(int l,int r) { 11 b[l]++; 12 b[r+1]--; 13 } 14 15 int main() { 16 scanf("%d",&n); 17 for(int i=1; i<=n; i++) { 18 scanf("%d %d",&l,&r); 19 insert(l,r); 20 mmin=min(mmin,l);//记录最左端的浇水的树 21 mmax=max(mmax,r);//记录最右端的浇水的树 22 } 23 int ans=0;//最多的浇水次数 24 int a=0; 25 for(int i=mmin; i<=mmax; i++) { 26 a=a+b[i]; 27 ans=max(a,ans); 28 } 29 printf("%d",ans); 30 return 0; 31 }
二维差分/差分矩阵
P3397 地毯
1 #include <iostream> 2 using namespace std; 3 const int N = 1010; 4 int n, m; 5 int a[N][N], b[N][N]; 6 int a1,b1,a2,b2; 7 int main() { 8 scanf("%d %d", &n, &m); 9 for(int j=1; j<=m; j++) { 10 cin>>a1>>b1>>a2>>b2; 11 b[a1][b1]++; 12 b[a1][b2+1]--; 13 b[a2+1][b1]--; 14 b[a2+1][b2+1]++; 15 //cout<<'a'<<endl; 16 } 17 18 for(int i=1; i<=n; i++) { 19 for(int j=1; j<=n; j++) { 20 b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1]; 21 cout<<b[i][j]<<' '; 22 } 23 cout<<endl; 24 } 25 return 0; 26 }