电子学会五级数据结构-前缀和差分
光骓者的荣耀
https://www.luogu.com.cn/problem/P5638
#include <bits/stdc++.h>
using namespace std;
const int maxn =1e6+5;
unsigned long long a[maxn];//输入数组
unsigned long long maxt;//可以跳过的最大距离
unsigned long long sum[maxn];//前缀和
int n,k;//n个城市 k一次可以跳个城市
//n个城市 n-1个距离
int main(){
scanf("%d %d",&n,&k);
for(int i=1;i<n;i++){
scanf("%llu",&a[i]);
sum[i] =sum[i-1]+a[i];//计算前缀和到sum
if(i>=k) {//计算往前到k节点的最大距离
maxt = max(maxt,sum[i] -sum[i-k]);
}
}
printf("%llu",sum[n-1]-maxt);//总距离-跳过的距离
return 0;
}
最大子段和
https://www.luogu.com.cn/problem/P1115
DP、前缀和、分治
https://www.cnblogs.com/zhb2000/archive/2021/03/10/maximum-subarray-sum.html
前缀和
#include<iostream>
using namespace std;
/*
前缀和
前缀和公式 s=a[j]-a[i-1] 为了使s尽可能大 所以需要让a[j]尽可能大 a[i-1]尽可能小
*/
int main(){
//mins记录最小值 有更小的需要更新
//sum记录到当前的最大值 有更大的需要更新
//ans默认为负无穷
int n,a,sum=0,mins=0,ans=-2e9+10;
cin>>n;
for(int i=0;i<n;i++){
cin>>a;
sum+=a;
if(sum-mins>ans){
ans=sum-mins;
}
if(mins>sum){
mins=sum;
}
}
cout<<ans;
return 0;
}
/*
原始序列
1 2 -5 8
前缀和 -从0开始累加 如果变到当前变为更小 说明之前对最大没贡献
1 3 -2 6
*/
地毯
https://www.luogu.com.cn/problem/P3397
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
int a[maxn][maxn];
int n,m;
//暴力模拟
int main(){
cin>>n>>m;
for(int t=0;t<m;t++){
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
for(int x=x1;x<=x2;x++){
for(int y=y1;y<=y2;y++){
a[x][y]++;
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<a[i][j]<<" ";
}
cout<<endl;
}
}
最大加权矩形
https://www.luogu.com.cn/problem/P1719
海底高铁
https://www.luogu.com.cn/problem/P3406
暴力
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m;//共n个城市 m要去的城市
long long ans;
//p[i]去的城市编号 cnt[i] i~i+1走过的次数
//A[i]i~i+1 纸质票费用 B[i]i~i+1 使用IC卡费用 C[i]IC卡的费用
int p[maxn],cnt[maxn],A[maxn],B[maxn],C[maxn];
//暴力算法
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){//输入所有要到达的城市
cin>>p[i];//每个要到达的城市
}
for(int i=1;i<n;i++){//输入 i~i+1的费用 A[i]纸质票费用 B[i]使用IC卡费用 C[i]IC卡的费用
cin>>A[i]>>B[i]>>C[i];
}
for(int i=2;i<=m;i++){//从第2个城市开始计算 i-1~i所有走的次数
if(p[i-1]<p[i]){//从小编号 走向大编号
for(int j=p[i-1];j<p[i];j++){
cnt[j]++;
}
}else{//从小编号 走向大编号 小到大=大到小
for(int j=p[i];j<p[i-1];j++){
cnt[j]++;
}
}
}
for(int i=1;i<n;i++){//每两个城市之间贪心使用费用小的
// A[i]*cnt[i]每段路的纸币费用*这段路走的次数
// B[i]*cnt[i]每段路刷IC卡费用*这段路走的次数
ans+=min(A[i]*cnt[i],B[i]*cnt[i]+C[i]);//所有费用和
}
cout<<ans;//总费用
}
差分
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m;//共n个城市 m要去的城市
long long ans;
//p[i]去的城市编号
//A[i]i~i+1 纸质票费用 B[i]i~i+1 使用IC卡费用 C[i]IC卡的费用
int p[maxn],d[maxn],sum[maxn];
//暴力算法
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){//输入所有要到达的城市
cin>>p[i];//每个要到达的城市
}
for(int i=2;i<=m;i++){//差分 一个区间增加 减小
int s=min(p[i],p[i-1]);//不确定前后大小 确定最小值
int e=max(p[i],p[i-1]);//不确定前后大小 确定最大值
d[s]++;//开始加
d[e]--;//结束减
}
for(int i=1;i<n;i++){//n个城市之间 n-1条路
sum[i]=sum[i-1]+d[i];//累计经过城市次数
}
for(int i=1;i<n;i++){//输入 i~i+1的费用 A[i]纸质票费用 B[i]使用IC卡费用 C[i]IC卡的费用
int A,B,C;
cin>>A>>B>>C;
ans+=min((long long)sum[i]*A,(long long)sum[i]*B+C);
}
cout<<ans;//总费用
}
领地选择
https://www.luogu.com.cn/problem/P2004
求和
https://www.luogu.com.cn/problem/P2671
借教室
https://www.luogu.com.cn/problem/P1083
作者:newcode 更多资源请关注纽扣编程微信公众号
从事机器人比赛、机器人等级考试、少儿scratch编程、信息学奥赛等研究学习