洛谷__P3800 Power 收集(单调队列+DP)
题目链接:P3800 Power 收集 - 洛谷
题目大意:
有一个 大小的矩阵,部分矩阵中的点带有价值
可以选择第一行的任何一个位置作为起点 .
对于当前的位置 (表示在第 行第 列)
可以转移到: 中任意一个点
并且获得当前所在点的价值
求 : 可以取得的最大价值之和
思路:
走到的每个点的最大价值肯定是由上一行某个点值转移过来的,
所以只与上一行的状态有关,无后效性,
表示在点 能到达的最大价值和 , 则有:
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#include<map>
#include<unordered_set>
#include<unordered_map>
#include<bitset>
#include<tuple>
#include<array>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/numeric>
#define inf 72340172838076673
#define int long long
#define endl '\n'
#define F first
#define S second
#define mst(a,x) memset(a,x,sizeof (a))
#define gmap __gnu_pbds::gp_hash_table
#define power __gnu_cxx::power
using namespace std;
typedef pair<int, int> pii;
const int N = 4008, mod = 998244353;
int n, m, k, t;
int f[N][N];
void dq(int i) {
deque<int> q;
for (int j = 1; j <= min(m, t); j++) {
while (q.size() && f[i - 1][q.back()] <= f[i - 1][j]) q.pop_back();
q.push_back(j);
}
for (int j = 1; j <= m; j++) {
int l = max(1ll, j - t);
while (q.size() && q.front() < l) q.pop_front();
int r = j + t;
if (r <= m) {
while (q.size() && f[i - 1][q.back()] <= f[i - 1][r]) q.pop_back();
q.push_back(r);
}
f[i][j] += f[i - 1][q.front()];
}
}
void solve() {
cin >> n >> m >> k >> t;
for (int i = 1; i <= k; i++) {
int a, b, c;
cin >> a >> b >> c;
f[a][b] = c;
}
for (int i = 2; i <= n; i++) dq(i);
int res = 0;
for (int i = 1; i <= m; i++) res = max(res, f[n][i]);
cout << res << endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T = 1;
// cin >> T;
while (T--) solve();
return 0;
}

浙公网安备 33010602011771号