單調佇列維護區間最值
阿新 • • 發佈:2020-08-05
假設求一個序列中所有長度為k的區間的最值,我們在求1到k區間的最值後,2到k+1區間的最值可以用2到k區間的最值與第k+1個值進行比較,可以通過單調佇列維護2到k區間的最值
2020牛客多校第二場,單調佇列維護二維區間最值
#include<bits/stdc++.h> #define ri register int #define ll long long #define EPS 1e-7 #define INF 0x7fffffff #define lb(x) x&(-x) #define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0) using namespace std; const inline int read(){ int k = 0, f = 1; char c = getchar();View Codefor(;!isdigit(c); c = getchar()) if(c == '-') f = -1; for(;isdigit(c); c = getchar()) k = k * 10 + c - '0'; return k * f; } int n, m, k; const int maxn = 5005; int a[maxn][maxn], h[maxn][maxn]; int que[maxn]; ll ans = 0; int gcd(int x,int y){return x%y==0?y:gcd(y,x%y);} void solve(){for(ri i = 1; i <= n; ++i) for(ri j = 1; j <= m; ++j) a[i][j] = i * j / gcd(i, j); for(ri i = 1; i <= n; ++i){ int head = 1, tail = 1; que[tail] = 0; for(ri j = 1; j < k; ++j){ while(tail >= head && a[i][j] > a[i][que[tail]]) tail--; que[++tail] = j; } for(ri j = k; j <= m; ++j){ while(tail >= head && j - que[head] >= k) head++; while(tail >= head && a[i][j] > a[i][que[tail]]) tail--; que[++tail] = j; h[i][j] = a[i][que[head]]; } } for(ri j = k; j <= m; ++j){ int head = 1, tail = 1; que[tail] = 0; for(ri i = 1; i < k; ++i){ while(tail >= head && h[i][j] > h[que[tail]][j]) tail--; que[++tail] = i; } for(ri i = k; i <= n; ++i){ while(tail >= head && i - que[head] >= k) head++; while(tail >= head && h[i][j] > h[que[tail]][j]) tail--; que[++tail] = i; ans += h[que[head]][j]; } } } int main(){ fast; cin >> n >> m >> k; solve(); cout << ans << "\n"; return 0; }