电子学会五级数据结构-前缀和差分

光骓者的荣耀
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

posted @ 2022-05-04 08:01  new-code  阅读(25)  评论(0编辑  收藏  举报