514-D 题目大意
给定\(n\)个人,每个人有\(m\)个属性,第\(i\)个人的第\(j\)个属性值为\(a[i][j]\)。
最多可以执行\(k\)次操作,每次操作选定一个属性,把所有人的该属性减\(1\),求一段最长的区间,满足执行所有操作之后该区间中所有人的所有属性全部为\(0\)。
Solution
转换一下思考方向,求一段最长的区间,满足区间中每项属性的最大值之和不大于\(k\)。
注意到单调性,固定右端点,移动左端点时,区间中所有属性的最大值之和一定是单调不增的。于是可以用双指针来枚举右端点寻找合法的最长区间。
剩下的就是如何快速得到区间中的某项属性的最大值,暴力枚举会使复杂度达到\(O(n^2m)\)级别,对于在双指针的应用场景维护区间最值,这时就应当想到使用单调队列进行优化。
时间复杂度\(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;
}
标签:队列,CF,int,vector,区间,514,单调,属性
From: https://www.cnblogs.com/fengxue-K/p/17963872