二维双指针
思路:考虑暴力做法,我们统计前缀和,然后枚举以
(
x
1
,
y
1
)
(x_1,y_1)
(x1,y1),
(
x
2
,
y
2
)
(x_2,y_2)
(x2,y2)为左上,右下顶点的矩阵有多少是合法的,那么,这样的时间复杂度为
n
4
n^4
n4。考虑进行优化,因为二维前缀和同样具有单调性,我们可以选择枚举左,右边界,然后对于枚举的左右边界,使用双指针进行上下边界的计算,这样的时间复杂度就降低为了
n
3
n^3
n3。
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<int, 3> ar;
int mod = 1e9+7;
// const int maxv = 4e6 + 5;
// #define endl "\n"
int a[1005][1005];
int s[1005][1005];
void solve()
{
int n,m,k;
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
s[i][j]=a[i][j]-s[i-1][j-1]+s[i][j-1]+s[i-1][j];
}
}
ll ans=0;
for(int i=1;i<=m;i++){
for(int j=i;j<=m;j++){
for(int c=1,t=1;c<=n;c++){
while(t<=c&&s[c][j]+s[t-1][i-1]-s[t-1][j]-s[c][i-1]>k) t++;
if(c>=t) ans+=c-t+1;
}
}
}
cout<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
t=1;
// cin>>t;
while(t--){
solve();
}
system("pause");
return 0;
}
二维滑动窗口
思路:首先考虑一维的情况,那么我们直接使用一个单调队列进行维护最大值和最小值即可,那么对于二维矩阵,以一个大小为
k
×
k
k\times k
k×k的矩阵为例,我们首先可以算出每一行中长度为k的最大值,此时我们知道了每一行的信息后,对于矩阵的最大值,肯定在前面已经算出来的行最大值中产生,我们再计算一遍列最大值即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<int, 3> ar;
int mod = 1e9+7;
// const int maxv = 4e6 + 5;
// #define endl "\n"
int n,m,k;
void solve()
{
cin>>n>>m>>k;
vector<vector<int>>a(n+5,vector<int> (m+5));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++) cin>>a[i][j];
}
vector<vector<int>> rminv(n+5,vector<int> (m+5)),rmaxv(n+5,vector<int> (m+5));
//计算行最大值,rmaxv[i][j]代表第i行(j-k+1,j)内的最大值,rminv同理
auto getmax=[](vector<int> a,vector<int>& rmaxv,int m)//单调队列维护滑动窗口
{
deque<int> q;
for(int i=1;i<=m;i++){
if(q.size()&&i-q.front()+1>k) q.pop_front();
while(q.size()&&a[q.back()]<=a[i]) q.pop_back();
q.push_back(i);
rmaxv[i]=a[q.front()];
}
};
auto getmin=[](vector<int> a,vector<int>& rminv,int m)
{
deque<int> q;
for(int i=1;i<=m;i++){
if(q.size()&&i-q.front()+1>k) q.pop_front();
while(q.size()&&a[q.back()]>=a[i]) q.pop_back();
q.push_back(i);
rminv[i]=a[q.front()];
}
};
for(int i=1;i<=n;i++){
getmax(a[i],rmaxv[i],m);
getmin(a[i],rminv[i],m);
}
int ans=2e9;
vector<int> cmaxv(n+5),cminv(n+5),b(n+5),c(n+5);
//b,c数组用于保存n行的行最大值和最小值;cmaxv即为对n行的最大值进行计算,得出整个矩阵的最大值。
for(int i=k;i<=m;i++){
for(int j=1;j<=n;j++){
b[j]=rmaxv[j][i];
c[j]=rminv[j][i];
}
getmax(b,cmaxv,n);
getmin(c,cminv,n);
for(int i=k;i<=n;i++) ans=min(ans,cmaxv[i]-cminv[i]);
}
cout<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
t=1;
// cin>>t;
while(t--){
solve();
}
system("pause");
return 0;
}
板子题,计算矩阵所有最大值的和即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 5e3 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<int, 3> ar;
int mod = 1e9+7;
// const int maxv = 4e6 + 5;
// #define endl "\n"
int n,m,k;
void solve()
{
cin>>n>>m>>k;
vector<vector<int>> a (n+5,vector<int> (m+5));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=lcm(i,j);
}
}
vector<vector<int>>rmaxv(n+5,vector<int> (m+5));
auto getmax=[](vector<int> a,vector<int>& rmaxv,int m)
{
deque<int> q;
for(int i=1;i<=m;i++){
if(q.size()&&i-q.front()+1>k) q.pop_front();
while(q.size()&&a[q.back()]<=a[i]) q.pop_back();
q.push_back(i);
rmaxv[i]=a[q.front()];
}
};
for(int i=1;i<=n;i++){
getmax(a[i],rmaxv[i],m);
}
ll ans=0;
vector<int> cmaxv(n+5),b(n+5);
for(int i=k;i<=m;i++){
for(int j=1;j<=n;j++){
b[j]=rmaxv[j][i];
}
getmax(b,cmaxv,n);
for(int i=k;i<=n;i++) ans+=(ll)cmaxv[i];
}
cout<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
t=1;
// cin>>t;
while(t--){
solve();
}
system("pause");
return 0;
}