蓝桥杯C++大学B组一个月冲刺记录2024/3/2

蓝桥杯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;



}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值