作业介绍
2026年编程兔冬令营集训第三场作业
1、差分 2、STL
1、通过维护相邻元素的差值,将区间操作转化为端点操作:
a.原数组差分d[i]=a[i]-a[i-1]
b.区间[L,R]加C → d[L] += C; d[R+1] -= C
c.通过差分数组d进行前缀和还原操作后的原数组a
#include<bits/stdc++.h>
using namespace std;
int a[200005],b[200005];
int n,p,x,y,z,ans=INT_MAX;
int main(){
cin>>n>>p;
for(int i=1;i<=n;++i){
cin>>a[i];
b[i] = a[i]-a[i-1];//原数组差分
}
while(p-->0){
cin>>x>>y>>z;
b[x]+=z;b[y+1]-=z;//区间[x,y]加上z
}
for(int i=1;i<=n;++i){
b[i]+= b[i-1];//差分数组前缀和,恢复成原数组
ans = min(ans,b[i]);
}
cout<<ans<<endl;
return 0;
}
2、利用差分的来处理,a[i]>a[i-1]需要补次数
#include<bits/stdc++.h>
using namespace std;
int a[100005];
int n,ans=0;
int main(){
cin>>n;
for(int i=1;i<=n;++i){
cin>>a[i];
// 差分,大的说明需要补次数
if (a[i]-a[i-1]>0) ans+=a[i]-a[i-1];
}
cout<<ans<<endl;
return 0;
}
3、有一个二维数组s[N][M],a[N][M]为s的差分矩阵,那么如下图所示:a矩阵中所有标记为蓝色的元素之和就是s[i,j],二维前缀和有:s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] +a[i][j];那么通过移项可以知道:a[i][j] = s[i][j] - s[i-1][j] - s[i][j-1] + s[i-1][j-1];这个公式非常重要,这既是差分矩阵的性质,也是我们求解差分矩阵的重要甚至是唯一的依据。
这里我们假设:我们要在s矩阵紫色位置所有元素+c,这个时候相当于对其差分矩阵a进行以下操作:
a[x1, y1] += c;
a[x1, y2 + 1] -= c;
a[x2 + 1, y1] -=c;
a[x2 + 1, y2 +1] += c;
大家可以结合下面的图片自行验证一下!
#include<iostream>
using namespace std;
const int N = 1010;
// a为s的差分矩阵,s为a的前缀和矩阵
int a[N][N], s[N][N];
// s数组有m行n列,进行q次操作
int m, n, q;
// 对a进行操作(插入)
// 表示对于s数组,以(x1,y1)为左上角,以(x2,y2)为右下角的子矩阵全部都+c
void insert(int x1, int y1, int x2, int y2, int c) {
a[x1][y1] += c;
a[x1][y2 + 1] -= c;
a[x2 + 1][y1] -= c;
a[x2 + 1][y2 + 1] += c;
}
int main() {
scanf("%d%d", &n, &q);
m=n;
// 操作q次
for(int i = 1; i <= q; i ++) {
int x1, y1, x2, y2, c=1;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
insert(x1, y1, x2, y2, c);
}
// 求出s数组(通过差分求前缀和)
for(int i = 1; i <= m; i ++) {
for(int j = 1; j <= n; j ++){
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
}
}
// 输出s数组
for(int i = 1; i <= m; i ++) {
for(int j = 1; j <= n; j ++) {
cout << s[i][j] <<" ";
}
cout << endl;
}
return 0;
}
4、在C++ STL(标准模板库)中,set 是一个自带“有序+去重”buff的容器,底层基于红黑树实现,既能自动排序元素,又能保证无重复值,日常开发中处理去重、有序遍历、快速查找等场景时特别好用。
https://mp.weixin.qq.com/s/lQtXpfdh2I83UXauSqnN2Q
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,ans=0;
string s;
set<string> st;//定义字符串类型的set
cin>>n;
for(int i=0;i<n;++i){
cin>>s;
st.insert(s);//直接存入st,自动去重排序
}
cout<<52-st.size()<<endl;//st.size()去重后的总数量
return 0;
}
5、思考一下这题跟上一题的相似点和不同点?本题需要统计重复数字出现的次数,明显set不能完全符合(只有去重无法统计),而开数组的话,数据范围太大。
在C++中,map 是一种关联容器,用于存储键值对(key-value),其中每个键(key)是唯一的,并且每个键都映射到一个值(value)。map 内部通常使用红黑树实现,因此其插入、删除和查找操作的时间复杂度都是对数级别的(O(log n))。
每一对中的第一个值称之为关键字(key),每个关键字只能在map中出现一次;第二个称之为该关键字的对应值(value)。
map适用题目:
a.元素去重,因为map的key也是不能重复的(梦回set)
b.统计数据出现的次数
c.需要将多个数据进行绑定处理的题目
#include <bits/stdc++.h>
using namespace std;
map<int, int> cnt;//定义map,第一维是key出现的数字,第二维是统计次数
int n, x;
int main(){
cin >> n;
while(n--){
cin >> x;
cnt[x]++;//类似数组使用,统计次数
}
for(auto x : cnt){//map是有序的,遍历输出
cout << x.first << " " << x.second << "\n";
}
return 0;
}
6、对比上题,key从数字换成了字符串
#include <bits/stdc++.h>
using namespace std;
map<string, int> cnt;//定义map,第一维是key出现的字符串,第二维是对应的数字
int n, q,x;
string s;
int main(){
cin >> n>>q;
while(n--){
cin>>s>>x;
cnt[s]=x;//s--x对应
}
while(q--){
cin>>s;
cout<<cnt[s]<<endl;//字符串下标的数组
}
return 0;
}
题目
认领作业后才可以查看作业内容。
- 状态
- 正在进行…
- 题目
- 6
- 开始时间
- 2026-2-3 0:00
- 截止时间
- 2027-1-1 23:59
- 可延期
- 24 小时