蓝桥杯C++大学B组一个月冲刺记录2024/3/1
规则:每日三题
1.空调
Farmer John 的 N头奶牛对他们牛棚的室温非常挑剔。
有些奶牛喜欢温度低一些,而有些奶牛则喜欢温度高一些。Farmer John 的牛棚包含一排 N个牛栏,编号为 1…N,每个牛栏里有一头牛。
第 i头奶牛希望她的牛栏中的温度是 pi,而现在她的牛栏中的温度是 ti
。
为了确保每头奶牛都感到舒适,Farmer John 安装了一个新的空调系统。
该系统进行控制的方式非常有趣,他可以向系统发送命令,告诉它将一组连续的牛栏内的温度升高或降低 1个单位——例如「将牛栏 5…8的温度升高 1个单位」。
一组连续的牛栏最短可以仅包含一个牛栏。
请帮助 Farmer John 求出他需要向新的空调系统发送的命令的最小数量,使得每头奶牛的牛栏都处于其中的奶牛的理想温度。
差分
不清楚为什么答案是取正数和与负数和的最大值
只记得AC的写法
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int M = 100010;
int pos[M];
int res[M];
int n;
int a = 0;
int b = 0;
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> pos[i];
for (int j = 1; j <= n; ++j) {
int t;
cin >> t;
res[j] = pos[j] - t;
}
for (int i = n; i >= 1; --i) {
res[i] -= res[i - 1];
if (res[i] > 0) a += res[i];
else b -= res[i];
}
cout << max(a, b) << endl;
return 0;
}
2.管道
(这个题的语文描述太差了就不贴了)
答案二分 + 区间合并
但是一直AC不了,de了半个小时才发现,q在check完没有clear掉
:D
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int M = 100010;
typedef long long LL;
typedef pair<int,int>PII;
PII p[M];
vector<PII>q;
vector<PII>::iterator it;
int n,len;
bool cmp(PII a,PII b){
return a.first < b.first;
}
bool check(int mid){
for(int i = 1;i <= n; ++i){
if(p[i].second <= mid){
int ll = max(1,p[i].first - (mid - p[i].second));
int rr = min((LL)len,(LL)p[i].first + (mid - p[i].second));
q.push_back({ll,rr});
}
}
sort(q.begin(),q.end(),cmp);
int st = -1,ed = -1;
for(int i = 0;i < q.size();++i){
if(q[i].first <= ed+1) ed = max(ed,q[i].second);
else{
st = q[i].first;
ed = q[i].second;
}
}
q.clear();
return st == 1&&ed == len;
}
int main(){
cin >> n >> len;
for(int i = 1;i <= n;++i){
cin >> p[i].first >> p[i].second;
}
LL l = 0,r = 2e9;
while(l < r){
int mid = (LL)(l+r)/2;
if(check(mid) == false) l = mid+1;
else r = mid;
}
cout << l << endl;
return 0;
}
3.统计子矩阵
给定一个 N×M的矩阵 A,请你统计有多少个子矩阵 (最小 1×1,最大 N×M) 满足子矩阵中所有数的和不超过给定的整数 K?
前缀和 + 双指针
1.本题最有意思的是对时间复杂度的考虑:
最暴力的做法是O(n^6)
但矩阵所有的数之和很容易想到二维前缀和,这样做法是O(n^4)
由于给定上下界之后,穷举l,r且子矩阵的和不能超过K。所以当 r 右移时 l 条件右移
所以使用双指针来优化,这样的做法是O(n^3)。就能过掉边界大小为500的所有数据了
2.ans = r - l + 1 需要思考一下是为什么。
#include<iostream>
#include<cstdio>
using namespace std;
const int MAx = 505;
int p[MAx][MAx];
int res[MAx][MAx];//记录前缀和
int N,M,K;
int main(){
cin >> N >> M >> K;
for(int i = 1;i <= N; ++i){
for(int j = 1;j <= M; ++j){
cin >> p[i][j];
res[i][j] = p[i][j] + res[i-1][j];
}
}
long long int ans = 0;
int sum = 0;
for(int i = 1;i <= N; ++i){
for(int j = i;j <= N; ++j){ //j是下界,i是上界
sum = 0;
for(int l = 1,r = 1;r <= M;++r){
sum += res[j][r] - res[i-1][r];
while(sum > K){
sum -= res[j][l] - res[i-1][l];
l++;
}
ans += r - l + 1;
}
}
}
cout << ans << endl;
}