Description
有一个 01
序列
a
=
(
a
1
,
a
2
,
⋯
,
a
n
)
a=(a_1,a_2,\cdots,a_n)
a=(a1,a2,⋯,an),同时有
m
m
m 个三元组
(
x
i
,
y
i
,
v
i
)
(x_i,y_i,v_i)
(xi,yi,vi).
定义
w
(
a
)
=
(
∑
i
=
1
m
v
i
×
[
(
∑
j
=
x
i
−
y
i
+
1
x
i
a
j
)
=
y
i
]
)
−
d
×
(
∑
i
=
1
n
a
i
)
\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) 最大,且序列中没有超过
k
k
k 个连续的 1
,求这个最大值,
a
a
a 可以为全 0
.
有
t
t
t 组测试数据.
Limitations
1
≤
t
≤
10
1 \le t \le 10
1≤t≤10
1
≤
n
,
d
,
v
i
≤
1
0
9
1 \le n,d,v_i \le 10^9
1≤n,d,vi≤109
1
≤
m
≤
1
0
5
1 \le m \le 10^5
1≤m≤105
0
≤
x
i
−
y
i
<
x
i
≤
n
0 \le x_i-y_i < x_i \le n
0≤xi−yi<xi≤n
2
s
,
512
MB
2\text{s},512\text{MB}
2s,512MB
Solution
显然要 DP
.
下记
l
i
=
x
y
−
y
i
+
1
,
r
i
=
x
i
l_i=x_y-y_i+1,\;r_i=x_i
li=xy−yi+1,ri=xi.
设
f
i
f_i
fi 为考虑
a
1
⋯
i
a_{1\cdots i}
a1⋯i 且
a
i
=
1
a_i=1
ai=1 的
w
(
a
)
\operatorname{w}(a)
w(a) 最大值,并设
g
i
=
max
j
=
1
i
f
i
g_i=\max\limits_{j=1}^i f_i
gi=j=1maxifi.
易得
f
i
=
max
j
=
i
−
k
i
{
g
j
−
1
−
(
i
−
j
)
×
d
+
∑
[
l
k
,
r
k
]
⊆
(
j
,
i
]
v
p
}
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) 的影响
h
i
h_i
hi,考虑
i
−
1
i-1
i−1 转移到
i
i
i 时
h
h
h 如何变化.
首先
a
j
⋯
i
a_{j\cdots i}
aj⋯i 中全为
1
1
1,所以对每个
j
∈
[
0
,
i
)
j\in[0,i)
j∈[0,i) 执行
h
j
←
h
j
−
d
h_j\gets h_j-d
hj←hj−d.
这时满足
r
k
=
i
r_k=i
rk=i 的三元组就可以被选择,所以对每个
r
k
=
i
,
j
∈
[
0
,
l
k
)
r _k=i,j\in[0,l_k)
rk=i,j∈[0,lk) 执行
h
j
←
h
j
+
v
k
h_j\gets h_j+v_k
hj←hj+vk.
然后可得 f i = max j = i − k i − 1 h j , g i = m a x ( g i − 1 , h i ) 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),发现 g i g_i gi 在 j = i + 1 j=i+1 j=i+1 时可取到,故执行 h i + 1 ← h i + 1 + g i h_{i+1}\gets h_{i+1}+g_i hi+1←hi+1+gi.
时间复杂度
O
(
n
log
n
)
O(n\log n)
O(nlogn).
离散化一下,只考虑连续段即可做到
O
(
m
log
m
)
O(m\log m)
O(mlogm).
Code
3.80 KB , 19.70 s , 42.75 MB (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;
}