差分、前缀和

2024-09-04 05:38
文章标签 差分 前缀

本文主要是介绍差分、前缀和,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

P8218 【深进1.例1】求区间和  (前缀和)

#include <bits/stdc++.h>
using namespace std;
int n, m, a[100010], sum[100010], ans, l, r;
int main()
{scanf("%d", &n);for(int i=1; i<=n; ++i){scanf("%d", &a[i]);sum[i]=sum[i-1]+a[i];}scanf("%d", &m);while(m--){scanf("%d %d", &l, &r);ans=sum[r]-sum[l-1];printf("%d\n", ans);}return 0;
}

P6568 [NOI Online #3 提高组] 水壶

#include <bits/stdc++.h>
using namespace std;
const int N=1000010;
int n, k, a[N], sum[N], ans;
int main()
{scanf("%d %d", &n, &k);for(int i=1; i<=n; ++i){scanf("%d", &a[i]);sum[i]=sum[i-1]+a[i];}for(int i=1; i+k<=n; ++i){ans=max(ans, sum[i+k]-sum[i-1]);}printf("%d", ans);return 0;
}

P1865 A % B Problem(判断质数+区间查询+前缀和)

#include <bits/stdc++.h>
using namespace std;
int l, r, n, m, sum[1000010];
bool check(int x)
{if(x<2){return false;}for(int i=2; i<=sqrt(x); ++i){if(x%i==0){return false;}}return true;
}
int main()
{scanf("%d %d", &n, &m);for(int i=2; i<=m; ++i){if(check(i)){sum[i]=sum[i-1]+1;}else{sum[i]=sum[i-1];}}while(n--){scanf("%d %d", &l, &r);if(l<1 || l>m || r<1 || r>m){printf("Crossing the line\n");}else if(l>r){printf("0\n");}else{printf("%d\n", sum[r]-sum[l-1]);}}return 0;
}

P5638 【CSGRound2】光骓者的荣耀

//前缀和
#include <bits/stdc++.h>
using namespace std;
int n, k;
long long a[1000006], sum[1000006], ans, mx;
int main()
{scanf("%d %d", &n, &k);for(int i=1; i<n; ++i){scanf("%lld", &a[i]);//前缀和, sum[i]表示从1号城市到i+1号城市走高速公路花的时间 //也就是第1条路到第i条路的总时间, 总共有n-1条路 sum[i]=sum[i-1]+a[i];}//不能传送 if(k==0){ans=sum[n-1]; }else if(k>=n-1){	//能直接传送到终点 ans=0;}else{//能传送连续的k条路, 相当于计算连续k条路的最大和mx, //然后用总的时间sum[n-1]减去求得的最大和mx就是答案 //第i条路~第i+k-1条路直接传送了 for(int i=1; i+k-1<n; ++i){
//			ans=min(ans, sum[n-1]-(sum[i+k-1]-sum[i-1]));mx=max(mx, sum[i+k-1]-sum[i-1]);}	ans=sum[n-1]-mx;}printf("%lld", ans);return 0;
}

P3406 海底高铁

#include <bits/stdc++.h>
using namespace std;
int n, m, p[100006], a[100006], b[100006], c[100006];
long long ans, cnt[100006];	//cnt[i]表示第i条铁路走的次数 
int main()
{scanf("%d %d", &n, &m);for(int i=1; i<=m; ++i){scanf("%d", &p[i]);}for(int i=1; i<n; ++i){//第i段铁路 可以理解为第i座城市——第i+1座城市之间的铁路 //a[i]表示第i段铁路原始票价//b[i]表示第i段铁路的折扣票价//c[i]表示第i段铁路IC卡的工本费 scanf("%d %d %d", &a[i], &b[i], &c[i]);}//差分//cnt[i]表示第i条铁路走的次数 for(int i=1; i<m; ++i){//p[i]和p[j]表示两座城市的编号 int from=min(p[i], p[i+1]);int to=max(p[i], p[i+1]);//从第from座城市出发到第to座城市, 会经过(第form)~(第to-1)条铁路, 所以前面+1, 后面-1 cnt[from]+=1;	cnt[to]-=1;}for(int i=1; i<n; ++i){//前缀和, 求出经过第i条铁路的次数 cnt[i]+=cnt[i-1];	//cnt[0]是0 //总共n-1段铁路, 每一段是买卡还是买票, 取决于://买卡的钱c[i]+坐的次数*折扣后的票价b[i] 和  坐的次数*原价a[i]的大小关系 	if(c[i]+cnt[i]*b[i]<cnt[i]*a[i]){	//买卡便宜 ans+=c[i]+cnt[i]*b[i];}else{	//直接买票便宜 ans+=cnt[i]*a[i];}}	printf("%lld", ans);return 0;	
}

P2367 语文成绩

#include <bits/stdc++.h>
using namespace std;
int n, p, x, y, z, mn=510000000, a[5000008], d[5000008];	//学生分数和增加的分数 
int main()
{scanf("%d %d", &n, &p);for(int i=1; i<=n; ++i){scanf("%d", &a[i]);}for(int i=1; i<=p; ++i){scanf("%d %d %d", &x, &y, &z);//区间修改//标记区间两端 d[x]+=z;d[y+1]-=z;	}//前缀和 for(int i=1; i<=n; ++i){d[i]=d[i-1]+d[i];	//对差分数组求前缀和 a[i]=a[i]+d[i];		//统一修改 mn=min(mn, a[i]);	//比较最值 }printf("%d", mn);return 0;
}

P1719 最大加权矩形(二维前缀和)

#include <bits/stdc++.h>
using namespace std;
//d[i][j]是二维前缀和数组, 表示从第一行第一列到第i行第j列形成的矩阵数字之和
int n, a[128][128], d[128][128], mx, cur;	 
int main()
{scanf("%d", &n);for(int i=1; i<=n; ++i){for(int j=1; j<=n; ++j){scanf("%d", &a[i][j]);}}//计算二维前缀和数组 for(int i=1; i<=n; ++i){	//子矩阵的右下角所在的行 for(int j=1; j<=n; ++j){	//子矩阵的右下角所在的列 d[i][j]=d[i][j-1]+d[i-1][j]-d[i-1][j-1]+a[i][j];}}for(int i=1; i<=n; ++i){	//子矩阵的左上角所在的行 for(int j=1; j<=n; ++j){	//子矩阵的左上角所在的列 //注意k从i开始 for(int k=i; k<=n; ++k){	//子矩阵的右下角所在的行//注意l从j开始for(int l=j; l<=n; ++l){	//子矩阵的右下角所在的列 //计算子矩阵的和cur=d[k][l]-d[k][j-1]-d[i-1][l]+d[i-1][j-1];mx=max(mx, cur);}}}}printf("%d", mx);return 0;
}

P2004 领地选择(二维前缀和)

//最大子矩阵简化版
#include <bits/stdc++.h>
using namespace std;
int n, m, c, x, y, ans, a[1006][1006], sum[1006][1006];
int main()
{scanf("%d %d %d", &n, &m, &c);for(int i=1; i<=n; ++i){for(int j=1; j<=m; ++j){scanf("%d", &a[i][j]);}}//维护一个二维前缀和 for(int i=1; i<=n; ++i){for(int j=1; j<=m; ++j){sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+a[i][j];}}//设一个擂主 x=1;y=1;ans=sum[c][c];//通过差分求从(i,j)到(i+c-1, j+c-1)的最大矩阵和 for(int i=1; i+c-1<=n; ++i){for(int j=1; j+c-1<=m; ++j){int ii=i+c-1;	//右下角横坐标 int jj=j+c-1; 	//右下角纵坐标 if(sum[ii][jj]-sum[i-1][jj]-sum[ii][j-1]+sum[i-1][j-1] > ans){x=i;y=j;ans=sum[ii][jj]-sum[i-1][jj]-sum[ii][j-1]+sum[i-1][j-1]; }}}printf("%d %d", x, y);return 0;
}

P3397 地毯(二维差分前缀和)

//二维差分 
#include <bits/stdc++.h>
using namespace std;
int n, m, sum, leftx, lefty, rightx, righty, ans[1002][1002], d[1002][1002];
int main()
{scanf("%d %d", &n, &m);	while(m--){scanf("%d %d %d %d", &leftx, &lefty, &rightx, &righty);for(int i=leftx; i<=rightx; ++i){d[i][lefty]+=1;d[i][righty+1]-=1;}		}for(int i=1; i<=n+1; ++i){for(int j=1; j<=n+1; ++j){sum+=d[i][j];ans[i][j]=sum;}}for(int i=1; i<=n; ++i){for(int j=1; j<=n; ++j){printf("%d ", ans[i][j]);}printf("\n");}return 0;
}

P2822 [NOIP2016 提高组] 组合数问题(组合数+二维前缀和)

#include <bits/stdc++.h>
using namespace std;
long long a[2001][2001];
int n, m, t, k, ans[2001][2001];
int main()
{scanf("%d %d", &t, &k);for(int i=0; i<=2000; ++i){a[i][0]=1;a[i][i]=1;}//杨辉三角计算组合数 for(int i=1; i<=2000; ++i){for(int j=1; j<=i; ++j){a[i][j]=(a[i-1][j-1]+a[i-1][j])%k;}}for(int i=1; i<=2000; ++i){for(int j=1; j<=i; ++j){//前缀和, 上加左、减左上、加自己 ans[i][j]=ans[i-1][j]+ans[i][j-1]-ans[i-1][j-1];if(a[i][j]==0){ans[i][j]++;}}//计算ans[i+1][i+1]时, 会用到ans[i][i+1], 由于前面没计算 ans[i][i+1]=ans[i][i];}while(t--){scanf("%d %d", &n, &m);if(m>n){printf("%d\n", ans[n][n]);	}else{printf("%d\n", ans[n][m]);	}}return 0;
}

P2280 [HNOI2003]激光炸弹

处理边界的一种方法

#include <bits/stdc++.h>
using namespace std;
int n, m, x, y, v, asd[5010][5010], cur, ans;
int main()
{scanf("%d %d", &n, &m);for(int i=1; i<=n; ++i){scanf("%d %d %d", &x, &y, &v);asd[x+1][y+1]=v;}for(int i=1; i<=5001; ++i){for(int j=1; j<=5001; ++j){asd[i][j]=asd[i][j-1]+asd[i-1][j]-asd[i-1][j-1]+asd[i][j];}}for(int i=1; i+m-1<=5001; ++i){for(int j=1; j+m-1<=5001; ++j){int xx=i+m-1;int yy=j+m-1;cur=asd[xx][yy]-asd[xx][j-1]-asd[i-1][yy]+asd[i-1][j-1];ans=max(ans, cur);}}printf("%d", ans);return 0;
}

处理边界的另一种方法

#include <bits/stdc++.h>
using namespace std;
int n, m, x, y, v, cur, ans, asd[5010][5010];
int main()
{scanf("%d %d", &n, &m);for(int i=1; i<=n; ++i){scanf("%d %d %d", &x, &y, &v);asd[x+1][y+1]=v;}for(int i=1; i<=5001; ++i){for(int j=1; j<=5001; ++j){asd[i][j]=asd[i][j-1]+asd[i-1][j]-asd[i-1][j-1]+asd[i][j];}}for(int i=m; i<=5001; ++i){for(int j=m; j<=5001; ++j){int starti=i-m+1;int startj=j-m+1;cur=asd[i][j]-asd[i][startj-1]-asd[starti-1][j]+asd[starti-1][startj-1];ans=max(ans, cur);}}printf("%d", ans);return 0;
}

P3131 [USACO16JAN]Subsequences Summing to Sevens S

(前缀和思维题)

#include <bits/stdc++.h>
using namespace std;
const int N=50010;
int n, a[N], sum[N], l[7], r[7], ans; 
int main()
{scanf("%d", &n);for(int i=1; i<=n; ++i){scanf("%d", &a[i]);sum[i]=(sum[i-1]+a[i])%7;if(!l[sum[i]]){		//第一次出现这个余数,  l[sum[i]]=i;	//记录第一次出现的下标 }r[sum[i]]=i;		//记录最后一次出现的下标 }for(int i=1; i<=6; ++i){ans=max(ans, r[i]-l[i]);	//如果没答案, 则ans为0 }ans=max(ans, r[0]);printf("%d", ans);return 0;
}

这篇关于差分、前缀和的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1135154

相关文章

poj 3159 (spfa差分约束最短路) poj 1201

poj 3159: 题意: 每次给出b比a多不多于c个糖果,求n最多比1多多少个糖果。 解析: 差分约束。 这个博客讲差分约束讲的比较好: http://www.cnblogs.com/void/archive/2011/08/26/2153928.html 套个spfa。 代码: #include <iostream>#include <cstdio>#i

poj 3169 spfa 差分约束

题意: 给n只牛,这些牛有些关系。 ml个关系:fr 与 to 牛间的距离要小于等于 cost。 md个关系:fr 与 to 牛间的距离要大于等于 cost。 隐含关系: d[ i ] <= d[ i + 1 ] 解析: 用以上关系建图,求1-n间最短路即可。 新学了一种建图的方法。。。。。。 代码: #include <iostream>#include

POJ 1364差分约束

给出n个变量,m个约束公式 Sa + Sa+1 + .... + Sa+b < ki or > ki ,叫你判断是否存在着解满足这m组约束公式。 Sa + Sa+1   +   .+ Sa+b =  Sum[a+b] - Sum[a-1]  . 注意加入源点n+1 。 public class Main {public static void main(Strin

【LeetCode热题100】前缀和

这篇博客共记录了8道前缀和算法相关的题目,分别是:【模版】前缀和、【模版】二维前缀和、寻找数组的中心下标、除自身以外数组的乘积、和为K的子数组、和可被K整除的子数组、连续数组、矩阵区域和。 #include <iostream>#include <vector>using namespace std;int main() {//1. 读取数据int n = 0, q = 0;ci

Python中差分进化differential_evolution的调用及参数说明

在场景应用中,要求我们的函数计算结果尽可能的逼近实际测量结果,可转化计算结果与测量结果的残差,通过最小化残差,便可求出最优的结果。但使用最小二乘等方法来计算时,常常会使迭代的结果显然局部最优点而导致结算错误。 差分进化原理 差分进化(Differential Evolution,DE)是一种基于群体差异的进化算法,其计算思想主要包括以下几个方面: 一、初始化种群 首先,随机生成一个初始种群

前缀和 — 利用前缀信息解决子数组问题

【前缀和的核心思想是预先处理数组来快速计算任意子数组的和,基本上用于数组和序列问题。】 前缀和算法具体步骤 构造前缀和数组: 给定一个数组nums,其前缀和数组prex定义为prex[i]表示为数组nums从起始位置到第i个位置的元素累加和。构建前缀和公式: p r e x [ i ] = n u m s [ i ] ( i = = 0 ) p r e x [ i ] = p r e x

每日一题~cf 970 div3 (A思维,B小模拟,C二分,D排列数建图成环,E 26个字母暴力+前缀和,F 逆元,G 数论gcd )

A 题意: 有 a 个1 ,b 个2.问是否能将这些数划分为两个数值相等的集合。 输出 YES 或者 NO —————— 问题等价于 将数组 分成两个数值相同的数组。所以sum 应该是偶数。也就是说 1 的个数是偶数。在i1的个数是偶数的情况下,将 2 分成两份,如果2 的个数是偶数,OK。如果是奇数那么需要1来补齐,如果1 的个数大于等于2那么可以补齐。(1 的个数是偶数,需要2个1来补齐,剩下

【数据结构-二维前缀和】力扣1504. 统计全 1 子矩形

给你一个 m x n 的二进制矩阵 mat ,请你返回有多少个 子矩形 的元素全部都是 1 。 示例 1: 输入:mat = [[1,0,1],[1,1,0],[1,1,0]] 输出:13 解释: 有 6 个 1x1 的矩形。 有 2 个 1x2 的矩形。 有 3 个 2x1 的矩形。 有 1 个 2x2 的矩形。 有 1 个 3x1 的矩形。 矩形数目总共 = 6 + 2 + 3 + 1 +

RS485差分信号不对称

在RS485总线通信中,差分信号不对称的问题时常出现,尤其是在总线未接从机设备的情况下。这一问题不仅影响通信质量,还可能导致信号传输错误。通过对实际波形、芯片手册及电路的深入分析,可以找出引发差分信号不对称的根本原因,并采取相应的解决措施。 问题描述 在RS485通信测试中,当总线上没有从机设备连接时,观察到RS485差分信号(A、B)关于地(GND)不对称。理想情况下,RS485的差分信

Python高效实现Trie(前缀树)及其插入和查找操作

Python高效实现Trie(前缀树)及其插入和查找操作 在Python面试中,考官通常会关注候选人的编程能力、问题解决能力以及对Python语言特性的理解。Trie(前缀树)是一种高效的数据结构,广泛应用于字符串处理、自动补全、拼写检查等场景。本文将详细介绍如何实现一个Trie,并提供插入和查找操作,确保代码实用性强,条理清晰,操作性强。 1. 引言 Trie(前缀树)是一种树形数据结构,