1. 程式人生 > 實用技巧 >2020牛客多校第二場F題Fake Maxpooling(單調佇列維護區間最值)

2020牛客多校第二場F題Fake Maxpooling(單調佇列維護區間最值)

題意:給你n*m的最小公倍數矩陣,求每個k*k方陣裡的的最大元素值的和

題解:單調佇列維護區間最值,先從左到右,記錄最大值到b陣列

  再從上到下,記錄最大值,ans+=最大值

最小公倍數矩陣暴力列舉O(n*m*logn) ,優化方法為O(nm),但是空間會多一倍,會被卡空間...

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=5e3+7; const ll mod =1e9+7; int ma[maxn][maxn],b[maxn][maxn]; //int Gcd[maxn][maxn]; int main(){ IOS int n,m,k; cin>>n>>m>>k; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ ma[i][j]=i/__gcd(i,j)*j; } } // for (int i = 1; i <= n; i ++)
// for (int j = 1; j <= m; j ++) // if (!Gcd[i][j]) // for (int k = 1; k * i <= n && k * j <= m; k ++) // Gcd[k * i][k * j] = k, ma[k * i][k * j] = i * j * k; int maxx=0; ll ans=0; deque<int> q; for(int i=1;i<=n;i++){
while(!q.empty()) q.pop_back(); q.push_back(0); for(int j=1;j<k;j++){ while(q.size()&&ma[i][q.back()] <=ma[i][j] ) q.pop_back(); q.push_back(j); } for(int j=k;j<=m;j++){ while(q.size() && q.front()<=j-k ) q.pop_front(); while(q.size() && ma[i][q.back()] <= ma[i][j]) q.pop_back(); q.push_back(j); b[i][j]=max(b[i][j],ma[i][q.front()]); } } // for(int i=1;i<=n;i++){ // for(int j=1;j<=m;j++){ // cout<<b[i][j]<<" "; // } // cout<<endl; // } for(int j=k;j<=m;j++){ while(!q.empty()) q.pop_back(); q.push_back(0); for(int i=1;i<k;i++){ while(q.size()&&b[q.back()][j]<=b[i][j]) q.pop_back(); q.push_back(i); } for(int i=k;i<=n;i++){ while(q.size()&&q.front()<=i-k) q.pop_front(); while(q.size()&&b[q.back()][j]<=b[i][j]) q.pop_back(); q.push_back(i); ans+=b[q.front()][j]; } } cout<<ans<<endl; return 0; }
View Code