2020牛客暑期多校訓練營(第二場) F Fake Maxpooling
阿新 • • 發佈:2020-07-15
這個題目本質是求,加入給一個長度為n的區間,求區間內,長度為k內的最大值是多少。因為題目時間限制,不能直接用線段樹等。於是關於最大值我們思考到了單調棧。但是單調棧只能處理區間[0,r]的最大值。所以我們還需要移動左指標,保證區間長度是k。故使用雙端佇列。佇列中單調遞減。
隊頭保證在區間[r-k+1,r]中,隊尾保證單調性正確。每一次取隊頭元素即可。
所以這道題我們預處理,先預處理n行,每一行中每一個點的區間最大值是多少,再計算每一列中,最大值是多少(使用行的最大值,這樣只有k個)。
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #include<climits> #include<stack> #include<vector> #include<queue> #include<set> #include<bitset> #include<map> //#include<regex> #include<cstdio> #include <iomanip> #pragma GCC optimize(2) #define up(i,a,b) for(int i=a;i<b;i++) #define dw(i,a,b) for(int i=a;i>b;i--) #define upd(i,a,b) for(int i=a;i<=b;i++) #define dwd(i,a,b) for(int i=a;i>=b;i--) //#define local typedef long long ll; typedef unsigned long long ull; const double esp = 1e-6; const double pi = acos(-1.0); const int INF = 0x3f3f3f3f; const int inf = 1e9; using namespace std; ll read() { char ch = getchar(); ll x = 0, f = 1; while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } typedef pair<int, int> pir; #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lrt root<<1 #define rrt root<<1|1 deque<int>dq; const int N = 5e3 + 10; int grp[N][N]; int dp[N][N]; int gcd(int a,int b) { return b ? gcd(b, a%b) : a; } int n, m, k; int main() { n = read(), m = read(), k = read(); upd(i, 1, n) { upd(j, 1, m) { grp[i][j] = i * j / gcd(i, j); } } upd(i, 1, n) { dq.clear(); upd(j, 1, m) { while (dq.size() && j - dq.front() >= k)dq.pop_front(); while (dq.size() && grp[i][dq.back()] < grp[i][j])dq.pop_back(); dq.push_back(j); dp[i][j] = grp[i][dq.front()]; } } ll sum = 0; upd(j, k, m) { dq.clear(); upd(i, 1, n) { while (dq.size() && i - dq.front() >= k)dq.pop_front(); while (dq.size() && dp[dq.front()][j] < dp[i][j])dq.pop_back(); dq.push_back(i); if (i >= k) sum += dp[dq.front()][j]; } } cout << sum << endl; return 0; }