当前位置: 首页 > news >正文

2024蓝桥杯省赛保奖突击班-Day2-前缀和、差分、尺取_笔记_练习题解

3月25日-课堂笔记

  • 前缀和预处理 O ( n ) \mathcal{O}(n) O(n)
s[1] = a[1];
for(int i = 2; i <= n; ++ i)s[i] = s[i - 1] + a[i];
  • 利用前缀和查询区间和 O ( 1 ) O(1) O(1)
long long calc(int l, int r) {return l == 1 ? s[r] : s[r] - s[l - 1];
}
  • 差分序列的求法
c[1] = a[1];
for(int i = 2; i <= n; ++ i) c[i] = a[i] - a[i - 1];
  • 原序列上区间[l, r]修改相当于差分序列上两个单点修改
c[l] += v;
c[r + 1] -= v;
  • 区间加等差数列对应二次差分序列上常数个单点修改
  • 一般等差数列: …, 0 , a , a + d , a + 2 d , … , a + ( k − 1 ) d , 0 , 0 , … 0, a, a+d, a+2 d, \ldots, a+(k-1) d, 0,0, \ldots 0,a,a+d,a+2d,,a+(k1)d,0,0,
  • 一次差分之后: …, 0 , a , d , d , … , d , − a − ( k − 1 ) d , 0 , … 0, a, d, d, \ldots, d,-a-(k-1) d, 0, \ldots 0,a,d,d,,d,a(k1)d,0,
  • 二次差分之后: …, 0 , a , d − a , 0 , … , 0 , − a − k d , a + ( k − 1 ) d , … 0, a, d-a, 0, \ldots, 0,-a-k d, a+(k-1) d, \ldots 0,a,da,0,,0,akd,a+(k1)d,
  • 尺取法
for(int l = 1, r = 0; r <= n; ++ l) {while(num < m && r < n) ...;if(...) break;...
}
  • 双栈法维护尺取
    插入/删除 -> 插入/合并

练习题解

B3612 求区间和

题目链接:B3612
参考思路

前缀和模板题。

C++参考代码
#include <iostream>
#include <vector>using namespace std;int main() {int n, m;cin >> n;vector<int> a(n), prefix_sum(n + 1, 0);for (int i = 0; i < n; ++i)cin >> a[i];for (int i = 1; i <= n; ++i)prefix_sum[i] = prefix_sum[i - 1] + a[i - 1];cin >> m;while (m--) {int l, r;cin >> l >> r;cout << prefix_sum[r] - prefix_sum[l - 1] << endl;}return 0;
}
Java参考代码
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int[] a = new int[n];int[] prefixSum = new int[n + 1];for (int i = 0; i < n; i++)a[i] = scanner.nextInt();for (int i = 1; i <= n; i++)prefixSum[i] = prefixSum[i - 1] + a[i - 1];int m = scanner.nextInt();while (m-- > 0) {int l = scanner.nextInt();int r = scanner.nextInt();System.out.println(prefixSum[r] - prefixSum[l - 1]);}}
}
Python参考代码
n = int(input())
a = list(map(int, input().split()))prefix_sum = [0] * (n + 1)
for i in range(1, n + 1):prefix_sum[i] = prefix_sum[i - 1] + a[i - 1]m = int(input())
for _ in range(m):l, r = map(int, input().split())print(prefix_sum[r] - prefix_sum[l - 1])

P2367 语文成绩

题目链接:P2367
参考思路
C++参考代码
#include <iostream>
#include <vector>using namespace std;int main() {int n, p;cin >> n >> p;vector<int> scores(n), diff(n, 0);for (int i = 0; i < n; ++i)cin >> scores[i];while (p--) {int x, y, z;cin >> x >> y >> z;diff[x - 1] += z;if(y < n) diff[y] -= z;}for (int i = 1; i < n; ++i)diff[i] += diff[i - 1];int min_score = scores[0] + diff[0];for (int i = 1; i < n; ++i) {scores[i] += diff[i];min_score = min(min_score, scores[i]);}cout << min_score << endl;return 0;
}
Java参考代码
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int p = scanner.nextInt();int[] scores = new int[n];int[] diff = new int[n];for (int i = 0; i < n; i++)scores[i] = scanner.nextInt();while (p-- > 0) {int x = scanner.nextInt();int y = scanner.nextInt();int z = scanner.nextInt();diff[x - 1] += z;if (y < n)diff[y] -= z;}int minScore = scores[0] + diff[0];for (int i = 1; i < n; i++) {diff[i] += diff[i - 1];scores[i] += diff[i];minScore = Math.min(minScore, scores[i]);}System.out.println(minScore);}
}
Python参考代码
n, p = map(int, input().split())
scores = list(map(int, input().split()))
diff = [0] * nfor _ in range(p):x, y, z = map(int, input().split())diff[x - 1] += zif y < n:diff[y] -= zmin_score = scores[0] + diff[0]
for i in range(1, n):diff[i] += diff[i - 1]scores[i] += diff[i]min_score = min(min_score, scores[i])print(min_score)

P3406 海底高铁

题目链接:P3406
思路:本题可以使用差分数组和前缀和求出每一段需要经过的次数 再用贪心策略在2种买票方式的最优中选择。
C++参考代码
#include <iostream>
#include <algorithm>using namespace std;
long long c[100005] = {0};
int main() {int n, m;cin >> n >> m;long long sum = 0, ans = 0;int p1 = 0, p2 = 0, a, b, c1;if (m > 0) {cin >> p1;}for (int i = 2; i <= m; i++) {cin >> p2;if (p1 < p2) {c[p1]++;c[p2]--;} else {c[p2]++;c[p1]--;}p1 = p2;}for (int i = 1; i < n; i++) {sum += c[i];cin >> a >> b >> c1;if (sum != 0) {ans += min(a * sum, b * sum + c1);}}if (m <= 1) {ans = 0;}cout << ans;return 0;
}
Java参考代码
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int m = scanner.nextInt();long[] c = new long[100005];long sum = 0, ans = 0;int p1 = 0, p2 = 0, a, b, c1;if (m > 0) {p1 = scanner.nextInt();}for (int i = 2; i <= m; i++) {p2 = scanner.nextInt();if (p1 < p2) {c[p1]++;c[p2]--;} else {c[p2]++;c[p1]--;}p1 = p2;}for (int i = 1; i < n; i++) {sum += c[i];a = scanner.nextInt();b = scanner.nextInt();c1 = scanner.nextInt();if (sum != 0) {ans += Math.min(a * sum, b * sum + c1);}}if (m <= 1) {ans = 0;}System.out.println(ans);scanner.close();}
}
Python参考代码
n, m = map(int, input().split())
c = [0] * 100005
sum = 0
ans = 0
P = list(map(int,input().split()))
p1 = P[0]
for i in range(1,len(P)):p2 = P[i]if p1 < p2:c[p1] += 1c[p2] -= 1else:c[p2] += 1c[p1] -= 1p1 = p2for i in range(1, n):sum += c[i]a, b, c1 = map(int, input().split())if sum != 0:ans += min(a * sum, b * sum + c1)if m <= 1:ans = 0print(ans)

P4552 IncDec Sequence

题目链接:P4552
参考思路:(这是一个比较困难的题)

题中要使所有数都一样。那么,也就是说,在差分的数组中,除了第一个数字外,其他的数字必须为0
那么我们要做的,就是使除了第一个数字外,其他的数字必须为0。
我们知道差分的公式为 c [ l ] + = v ; c [ r + 1 ] − = v c[l]+=v;c[r+1]-=v c[l]+=v;c[r+1]=v;
那么我们可以得出结论:
最少次数就是在差分序列中的正数相加的值负数相加的绝对值的较大值。
那么,如何解决方法的种数呢?这又是转换法。
思考,差分后的第一个数字的种数是不是就是题目要求的方法数量。
那么要改变差分的第一个数字,是不是以 c [ 1 ] + + , c [ i ] − − 或 c [ 1 ] − − , c [ i ] + + c[1]++,c[i]--或c[1]--,c[i]++ c[1]++,c[i]c[1],c[i]++的方法来改变。
由于要求步数最少,要在差分数组中所有的正数或负数已经和其他数相互抵消完后,才能用 c [ 1 ] c[1] c[1]来勾兑。
那么答案就是正数和负数的绝对值的最大值减去正数和负数的绝对值的最小值。

C++参考代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,sum1=0,sum2=0;
int main()
{cin >> n;vector<ll>a(n+1,0);for(int i = 1 ; i <= n ; i++){cin >> a[i];}vector<ll>C(n+1,0);for(int i = 2 ; i <= n ; i++){C[i] = a[i] - a[i - 1];if(C[i] > 0) sum1 += C[i];else sum2 -= C[i];}cout << max(sum1 , sum2) << endl ;cout << abs(sum1 - sum2) + 1 << endl ;return 0;
}
Java参考代码
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();long[] a = new long[n + 1];  for (int i = 1; i <= n; i++) {a[i] = scanner.nextLong();}long[] C = new long[n + 1];  long sum1 = 0, sum2 = 0;for (int i = 2; i <= n; i++) {C[i] = a[i] - a[i - 1];if (C[i] > 0) sum1 += C[i];else sum2 -= C[i];}System.out.println(Math.max(sum1, sum2));System.out.println(Math.abs(sum1 - sum2) + 1);scanner.close();}
}
Python参考代码
n = int(input())
a = [0] * (n + 1)  
for i in range(1, n + 1):a[i] = int(input())C = [0] * (n + 1)
sum1 = sum2 = 0
for i in range(2, n + 1):C[i] = a[i] - a[i - 1]if C[i] > 0:sum1 += C[i]else:sum2 -= C[i]  print(max(sum1, sum2))
print(abs(sum1 - sum2) + 1)
http://www.lryc.cn/news/328418.html

相关文章:

  • C++基础之虚函数(十七)
  • 快速入门Kotlin①基本语法
  • 【理解指针(四)】
  • Ribbon简介
  • 【感悟《剑指offer》典型编程题的极练之路】02字符串篇!
  • 通过 Docker 实现国产数据库 OpenGauss 开发环境搭建
  • 【Java】LinkedList模拟实现
  • ubuntu下mysql常用命令
  • 燃气官网安全运行监测系统-阀井燃气监测仪-旭华智能
  • vue 文件预览(docx、.xlsx、pdf)
  • 云架构(二) 大使模式
  • .NET Path类库的特殊方法
  • 【JVM】JVM常用性能调优参数详细介绍
  • React中的受控组件与非受控组件
  • uniapp实现u-datetime-picker时间选择器的默认日期定位,解决default-value不生效问题
  • react native 使用ScrollView实现下拉更新,上拉加载更多
  • vue2完结
  • 前端网页之间传递参数
  • 【常见面试题】Golang中,协程数最多可以开多少个?
  • RabbitMQ基础笔记
  • 大型项目管理神器:掌握yarn monorepo的安装和使用
  • 算法打卡day28|贪心算法篇02|Leetcode 122.买卖股票的最佳时机 II、55. 跳跃游戏、45.跳跃游戏 II
  • 2013年认证杯SPSSPRO杯数学建模A题(第一阶段)护岸框架全过程文档及程序
  • 【3】3道链表力扣题:删除链表中的节点、反转链表、判断一个链表是否有环
  • mongodb sharding分片模式的集群数据库,日志治理缺失导致写入数据库报错MongoWriteConcernException的问题总结(上)
  • 苹果Mac OS系统上安装brew
  • 应用侧渲染流程
  • 学生党开放式运动耳机怎么选?五款超高销量高性价比品牌推荐
  • 服务器中有g++,但是查询不到,Command ‘g++‘ not found
  • count(“0“),split() ,sys.stdin.readline() ,matrix.append, input().strip()