前缀和 和 差分

前缀和

定义

前缀和可以简单理解为「数列的前 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 }

 

posted @ 2023-03-10 17:15  关于42号星球  阅读(70)  评论(0编辑  收藏  举报