CF-514-D-单调队列

514-D 题目大意

给定n个人,每个人有m个属性,第i个人的第j个属性值为a[i][j]

最多可以执行k次操作,每次操作选定一个属性,把所有人的该属性减1,求一段最长的区间,满足执行所有操作之后该区间中所有人的所有属性全部为0


Solution

转换一下思考方向,求一段最长的区间,满足区间中每项属性的最大值之和不大于k

注意到单调性,固定右端点,移动左端点时,区间中所有属性的最大值之和一定是单调不增的。于是可以用双指针来枚举右端点寻找合法的最长区间。

剩下的就是如何快速得到区间中的某项属性的最大值,暴力枚举会使复杂度达到O(n2m)级别,对于在双指针的应用场景维护区间最值,这时就应当想到使用单调队列进行优化。

时间复杂度O(nm)

#include<bits/stdc++.h>
using namespace std;
using ll=long long;

int main() {
    int n,m,k;
    cin>>n>>m>>k;
    vector<vector<int>> a(n,vector<int>(m));
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>a[i][j];
        }
    }
    vector<deque<int>> q(m);
    int ans=0;
    vector<int> res(m);
    for(int l=0,r=0;r<n;r++){
        int sum=0;
        for(int j=0;j<m;j++){
            while(!q[j].empty()&&a[q[j].back()][j]<a[r][j]){
                q[j].pop_back();
            }
            q[j].push_back(r);
            sum+=a[q[j].front()][j];
        }
        while(l<=r&&sum>k){
            l++;
            for(int i=0;i<m;i++){
                while(!q[i].empty()&&q[i].front()<l){
                    sum-=a[q[i].front()][i];
                    q[i].pop_front();
                    if(q[i].size()) sum+=a[q[i].front()][i];
                }
            }
        }
        if(r-l+1>ans){
            ans=r-l+1;
            for(int i=0;i<m;i++) res[i]=a[q[i].front()][i];
        }
    }
    for(int i=0;i<m;i++){
        cout<<res[i]<<" ";
    }
    return 0;
}
posted @   fengxue-K  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示