Description
有一个 01 序列 a=(a1,a2,⋯ ,an)a=(a_1,a_2,\cdots,a_n)a=(a1,a2,⋯,an),同时有 mmm 个三元组 (xi,yi,vi)(x_i,y_i,v_i)(xi,yi,vi).
定义 w(a)=(∑i=1mvi×[(∑j=xi−yi+1xiaj)=yi])−d×(∑i=1nai)\operatorname{w}(a)=(\sum\limits_{i=1}^m v_i\times[(\sum\limits_{j=x_i-y_i+1}^{x_i}a_j) = y_i])-d\times(\sum\limits_{i=1}^n a_i)w(a)=(i=1∑mvi×[(j=xi−yi+1∑xiaj)=yi])−d×(i=1∑nai).
你需要确定这个序列,使得 w(a)\operatorname{w}(a)w(a) 最大,且序列中没有超过 kkk 个连续的 1,求这个最大值,aaa 可以为全 0.
有 ttt 组测试数据.
Limitations
1≤t≤101 \le t \le 101≤t≤10
1≤n,d,vi≤1091 \le n,d,v_i \le 10^91≤n,d,vi≤109
1≤m≤1051 \le m \le 10^51≤m≤105
0≤xi−yi<xi≤n0 \le x_i-y_i < x_i \le n0≤xi−yi<xi≤n
2s,512MB2\text{s},512\text{MB}2s,512MB
Solution
显然要 DP.
下记 li=xy−yi+1, ri=xil_i=x_y-y_i+1,\;r_i=x_ili=xy−yi+1,ri=xi.
设 fif_ifi 为考虑 a1⋯ia_{1\cdots i}a1⋯i 且 ai=1a_i=1ai=1 的 w(a)\operatorname{w}(a)w(a) 最大值,并设 gi=maxj=1ifig_i=\max\limits_{j=1}^i f_igi=j=1maxifi.
易得 fi=maxj=i−ki{gj−1−(i−j)×d+∑[lk,rk]⊆(j,i]vp}f_i=\max\limits_{j=i-k}^i\{g_{j-1}-(i-j)\times d + \sum\limits_{[l_k,r_k]\subseteq (j,i]} v_p\}fi=j=i−kmaxi{gj−1−(i−j)×d+[lk,rk]⊆(j,i]∑vp}
显然可以用线段树维护每个决策对 w(a)\operatorname{w}(a)w(a) 的影响 hih_ihi,考虑 i−1i-1i−1 转移到 iii 时 hhh 如何变化.
首先 aj⋯ia_{j\cdots i}aj⋯i 中全为 111,所以对每个 j∈[0,i)j\in[0,i)j∈[0,i) 执行 hj←hj−dh_j\gets h_j-dhj←hj−d.
这时满足 rk=ir_k=irk=i 的三元组就可以被选择,所以对每个 rk=i,j∈[0,lk)r
_k=i,j\in[0,l_k)rk=i,j∈[0,lk) 执行 hj←hj+vkh_j\gets h_j+v_khj←hj+vk.
然后可得 fi=maxj=i−ki−1hj, gi=max(gi−1,hi)f_i=\max\limits_{j=i-k}^{i-1} h_j,\;g_i=max(g_{i-1},h_i)fi=j=i−kmaxi−1hj,gi=max(gi−1,hi),发现 gig_igi 在 j=i+1j=i+1j=i+1 时可取到,故执行 hi+1←hi+1+gih_{i+1}\gets h_{i+1}+g_ihi+1←hi+1+gi.
时间复杂度 O(nlogn)O(n\log n)O(nlogn).
离散化一下,只考虑连续段即可做到 O(mlogm)O(m\log m)O(mlogm).
Code
3.80KB,19.70s,42.75MB (in total, C++20 with O2)3.80\text{KB},19.70\text{s},42.75\text{MB}\;\texttt{(in total, C++20 with O2)}3.80KB,19.70s,42.75MB(in total, C++20 with O2)
// Problem: P9871 [NOIP2023] 天天爱打卡
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P9871
// Memory Limit: 512 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;
template<class T>
bool chmax(T &a, const T &b){
if(a < b){ a = b; return true; }
return false;
}
template<class T>
bool chmin(T &a, const T &b){
if(a > b){ a = b; return true; }
return false;
}
const i64 inf = 1e13;
struct Node {
int l, r;
i64 max, tag;
};
using Tree = vector<Node>;
inline int ls(int u) { return 2 * u + 1; }
inline int rs(int u) { return 2 * u + 2; }
inline void build(Tree& tr, int u, int l, int r) {
tr[u].l = l;
tr[u].r = r;
tr[u].max = -inf;
tr[u].tag = 0;
if (l == r) return;
const int mid = (l + r) >> 1;
build(tr, ls(u), l, mid);
build(tr, rs(u), mid + 1, r);
}
inline void pushup(Tree& tr, int u) {
tr[u].max = max(tr[ls(u)].max, tr[rs(u)].max);
}
inline void apply(Tree& tr, int u, i64 val) {
tr[u].max += val;
tr[u].tag += val;
}
inline void pushdown(Tree& tr, int u) {
if (tr[u].tag) {
apply(tr, ls(u), tr[u].tag);
apply(tr, rs(u), tr[u].tag);
tr[u].tag = 0;
}
}
inline void update(Tree& tr, int u, int l, int r, i64 val) {
if (l > r) return;
if (l <= tr[u].l && tr[u].r <= r) return apply(tr, u, val);
const int mid = (tr[u].l + tr[u].r) >> 1;
pushdown(tr, u);
if (l <= mid) update(tr, ls(u), l, r, val);
if (r > mid) update(tr, rs(u), l, r, val);
pushup(tr, u);
}
inline i64 query(Tree& tr, int u, int l, int r) {
if (l <= tr[u].l && tr[u].r <= r) return tr[u].max;
const int mid = (tr[u].l + tr[u].r) >> 1;
i64 res = -inf;
pushdown(tr, u);
if (l <= mid) res = max(res, query(tr, ls(u), l, r));
if (r > mid) res = max(res, query(tr, rs(u), l, r));
return res;
}
inline void solve() {
int n, m, k, d;
scanf("%d %d %d %d", &n, &m, &k, &d);
vector<array<int, 3>> A(m);
vector<int> nums{n - 1};
for (auto& [l, r, v] : A) {
int x, y;
scanf("%d %d %d", &x, &y, &v);
nums.push_back(l = x - y + 1);
nums.push_back(r = x);
}
sort(nums.begin(), nums.end());
nums.erase(unique(nums.begin(), nums.end()), nums.end());
for (auto& [l, r, _] : A) {
l = lower_bound(nums.begin(), nums.end(), l) - nums.begin();
r = lower_bound(nums.begin(), nums.end(), r) - nums.begin();
}
sort(A.begin(), A.end(), [&](const array<int, 3>& a, const array<int, 3>& b) {
return a[1] < b[1];
});
vector dp(nums.size(), array<i64, 2>{-inf, -inf});
Tree tr(nums.size() << 2);
build(tr, 0, 0, nums.size() - 1);
update(tr, 0, 0, 0, inf);
for (int i = 0, j = 0, p = 0; i < nums.size(); i++) {
if (i > 0) update(tr, 0, 0, i - 1, -d * (nums[i] - nums[i - 1]));
while (nums[i] - nums[j] + 1 > k) j++;
while (p < m && A[p][1] == i) {
update(tr, 0, 0, A[p][0], A[p][2]);
p++;
}
dp[i][0] = max(0LL, i > 0 ? max(dp[i - 1][0], dp[i - 1][1]) : 0LL);
dp[i][1] = query(tr, 0, j, i) - d;
if (i + 1 < nums.size()) {
if (nums[i + 1] - nums[i] == 1) update(tr, 0, i + 1, i + 1, inf + dp[i][0]);
else update(tr, 0, i + 1, i + 1, inf + max(dp[i][0], dp[i][1]));
}
}
printf("%lld\n", max(dp.back()[0], dp.back()[1]));
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int c, t;
scanf("%d %d", &c, &t);
while (t--) solve();
return 0;
}
934

被折叠的 条评论
为什么被折叠?



