单调序列优化dp
单调队列求最大最小值……
首先,我们用一个单调队列维护行最小值
如果发现队首的元素“过期”了,那么就把它丢掉
如果队尾元素的值小于(大于)当前的值,那么就把它丢掉
例如:
模拟操作:
这里要注意的是我没有将“过期”元素丢掉,我们需要将“过期元素”丢掉
像这样处理每一行,再用处理完每一行的结果当作Map去处理每一列
总时间复杂度: O(n2)
这样就能得到正解
Code:
/**************************************************************
Problem: 1047
User: wohenshuai
Language: C++
Result: Accepted
Time:3264 ms
Memory:15460 kb
****************************************************************/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int a,b,n;
int map[1100][1100];
void Input()
{
scanf("%d%d%d",&a,&b,&n);
for(int i=1;i<=a;i++)
for(int j=1;j<=b;j++)
scanf("%d",&map[i][j]);
}
int head,tail;
int lmax[1100][1100],lmin[1100][1100];
struct node
{
int val,pos;
}list[1100];
int ans;
void Solve()
{
for(int i=1;i<=a;i++)
{
head=tail=1;
for(int j=1;j<=b;j++)
list[j].val=list[j].pos=0;
for(int j=1;j<=b;j++)
{
while(map[i][j]>=list[tail-1].val&&head<tail)
{
tail--;
}
list[tail].val=map[i][j]; list[tail].pos=j; tail++;
while(list[head].pos==j-n) head++;
if(j>=n) lmax[i][j]=list[head].val;
}
}
for(int i=1;i<=a;i++)
{
head=tail=1;
for(int j=1;j<=b;j++)
list[j].val=list[j].pos=0;
for(int j=1;j<=b;j++)
{
while(map[i][j]<=list[tail-1].val&&head<tail)
{
tail--;
}
list[tail].val=map[i][j]; list[tail].pos=j; tail++;
while(list[head].pos==j-n) head++;
if(j>=n)lmin[i][j]=list[head].val;
}
}
ans=1000000001;
for(int i=n;i<=a;i++)
for(int j=n;j<=b;j++)
{
int minn=1000000001,maxx=-1;
for(int k=0;k<n;k++)
{
minn=min(lmin[i-k][j],minn);
maxx=max(lmax[i-k][j],maxx);
}
ans=min(ans,maxx-minn);
}
}
void Output()
{
printf("%d\n",ans);
}
int main()
{
Input();
Solve();
Output();
return 0;
}