题目链接:https://ac.nowcoder.com/acm/contest/5667/F
这道题我们队之前没用过单调队列,这道题用二维线段树其实有点杀鸡用宰牛刀的感觉。并且由于数据量的原因导致二位线段树不用树套树会tle,用树套树会mle。
预备知识:
单调队列:
单调队列要从一个比较经典的问题说起来
这道题的题意是用一个固定长度的窗口,在一个数列上从左向右移动,找到每个窗口覆盖区域里的最大值。
暴力比较:O(N^2)
复杂度高的原因是在求解f(i)的时候,重复比较了它前面的m-1个数。
单调队列优化:O(N)
基本思想:
同样维护队首元素作为答案,去掉多余元素。(维护单调性)
队列中的每一个元素用一个二元组(id,val)表示,每次从队尾入队,删除队尾的无用元素,保证编号递增,值递减。
复杂度分析:
由于每个元素只会进队和被删掉(出队)一次,故复杂度为O(N)
代码实现:
数据结构:双端队列deque
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> res;
if(nums.empty() || k==0)
return res;
deque<int> que;
//先处理前k个元素,此时不需要输出
for(int i=0;i<k;++i){
//如果队尾元素不比新元素大,就将队尾元素弹出
while(!que.empty() && nums[que.back()]<=nums[i])
que.pop_back();
que.push_back(i);
}
//队首元素就是此时的最大值
res.push_back(nums[que.front()]);
//处理后面的元素,每次for循环都会输出一次
for(int i=k;i<nums.size();++i){
while(!que.empty() && nums[que.back()]<=nums[i])
que.pop_back();
que.push_back(i);
//如果队首元素出了窗口的范围,则弹出
if(!que.empty() && que.front()<i-k+1)
que.pop_front();
res.push_back(nums[que.front()]);
}
return res;
}
学习完单调队列回来再看这道题是不是就很简单啦 ^_^
解题思路:
对每一行都求一遍maxSlidingWindow,并把结果保存在res数组中。总共有n行,每行是O(m)
然后对res的每一列求一遍maxSlidingWindow,因为每个window中的k个数分别是各k行的k列的最大值,即求得的就是kk个数的最大值,总共有m列,每列是O(n)
最后的代码复杂度是O(nm)。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int lcm[5010][5010];
int res[5010][5010], cnt;
int gcd(int a, int b) {
return b ? gcd(b, a%b) : a;
}
int main()
{
int n, m, k;
scanf("%d%d%d",&n,&m,&k);
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
lcm[i][j] = i*j/gcd(i,j);
}
}
deque<int> que;
for(int i = 1; i <= n; i++)
{
cnt = 0; // res
que.clear();
for(int j = 1; j <= k; j++) {
while(!que.empty() && lcm[i][que.back()]<=lcm[i][j])
que.pop_back();
que.push_back(j);
}
res[i][++cnt] = lcm[i][que.front()];
for(int j = k+1; j <= m; j++) {
while(!que.empty() && lcm[i][que.back()]<=lcm[i][j])
que.pop_back();
que.push_back(j);
if(!que.empty() && que.front()<j-k+1)
que.pop_front();
res[i][++cnt] = lcm[i][que.front()];
}
}
ll result = 0;
for(int j = 1; j <= cnt; j++)
{
que.clear();
for(int i = 1; i <= k; i++) {
while(!que.empty() && res[que.back()][j]<=res[i][j])
que.pop_back();
que.push_back(i);
}
result += res[que.front()][j];
for(int i = k+1; i <= n; i++) {
while(!que.empty() && res[que.back()][j]<=res[i][j])
que.pop_back();
que.push_back(i);
if(!que.empty() && que.front()<i-k+1)
que.pop_front();
result += res[que.front()][j];
}
}
printf("%lld\n",result);
}

京公网安备 11010502036488号