单调队列维护区间最值
假设求一个序列中所有长度为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(); for(;!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; }
Never say never.


浙公网安备 33010602011771号