Music Festival
我们设状态为当前的炫酷值为 \(i\),则 \(dp_i\) 表示炫酷值,然后将每个专辑按照最大值排序即可
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
struct node {
vector<int> a;
int maxi;
}x[N];
int t, n, k[N], tr[N * 4], p[N], cnt, dp[N];
bool cmp(node &_x, node &_y) {
return _x.maxi < _y.maxi;
}
void build(int i, int l, int r) {
if (l == r) {
tr[i] = 0;
return ;
}
int mid = (l + r) >> 1;
build(i * 2, l, mid);
build(i * 2 + 1, mid + 1, r);
tr[i] = 0;
}
int query(int i, int l, int r, int x, int y) {
if (x > y) {
return 0;
}
if (l > y || r < x) {
return 0;
}
if (l >= x && r <= y) {
return tr[i];
}
int mid = (l + r) >> 1;
return max(query(i * 2, l, mid, x, y), query(i * 2 + 1, mid + 1, r, x, y));
}
void modify(int i, int l, int r, int p) {
if (l == r) {
tr[i] = max(tr[i], dp[p]);
return ;
}
int mid = (l + r) >> 1;
if (mid >= p) modify(i * 2, l, mid, p);
else modify(i * 2 + 1, mid + 1, r, p);
tr[i] = max(tr[i * 2], tr[i * 2 + 1]);
}
void Solve() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> k[i];
for (int j = 1, tmp; j <= k[i]; j++) {
cin >> tmp;
x[i].a.push_back(tmp);
x[i].maxi = max(x[i].maxi, tmp);
p[++cnt] = tmp;
}
}
sort(p + 1, p + cnt + 1);
cnt = unique(p + 1, p + cnt + 1) - p - 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < x[i].a.size(); j++) {
x[i].a[j] = lower_bound(p + 1, p + cnt + 1, x[i].a[j]) - p;
}
}
sort(x + 1, x + n + 1, cmp);
for (int i = 1; i <= n; i++) {
int u = 0, maxx = 0, d = 0;
for (auto cur : x[i].a) {
u = max(u, cur);
if (cur > maxx) {
maxx = cur;
d = max(d + 1, query(1, 1, cnt, 1, cur - 1) + 1);
dp[cur] = max(dp[cur], d);
}
else dp[cur] = max(dp[cur], 1);
}
modify(1, 1, cnt, u);
}
int ans = 0;
for (int i = 1; i <= cnt; i++) {
ans = max(ans, dp[i]);
}
cout << ans << "\n";
for (int i = 1; i <= n; i++) {
x[i].a.clear(), x[i].maxi = 0;
}
fill(dp + 1, dp + cnt + 1, 0);
build(1, 1, cnt);
cnt = 0;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> t;
while (t--) {
Solve();
}
return 0;
}
Array Collapse
我们可以用单调队列求出上一个比它小的,然后设 \(dp_{i, 0/1}\) 表示当前选到第几个,选或不选
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e5 + 5, mod = 998244353;
int t, n, a[N], dp[N][2], l[N], sum[N];
void Solve() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
stack<int> stk;
for (int i = 1; i <= n; i++) {
while (!stk.empty() && a[stk.top()] >= a[i]) {
stk.pop();
}
if (stk.empty()) {
l[i] = 0;
}
else l[i] = stk.top();
stk.push(i);
}
dp[0][1] = 1;
sum[0] = 1;
for (int i = 1; i <= n; i++) {
int p = l[i];
if (p) {
dp[i][0] = (dp[p][0] + dp[p][1]) % mod;
}
else dp[i][0] = 0;
dp[i][1] = ((dp[p][0] + sum[i - 1] - ((!p) ? 0 : sum[p - 1])) % mod + mod) % mod;
sum[i] = sum[i - 1] + dp[i][1];
sum[i] %= mod;
}
cout << (dp[n][0] + dp[n][1]) % mod << "\n";
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> t;
while (t--) {
Solve();
}
return 0;
}
Intervals
我们可以维护 \(dp_i\) 表示第 \(i\) 个数字为 \(1\) 的最大价值,那么我们考虑他从哪里转移而来如果 \(j\) 如果 \(j >= l[i]\) 那么可以获得当前的价值,这样搞个线段树即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 5;
int n, m, l[N], r[N], a[N], tr[N * 4], lazy[N * 4], sum, dp[N], tot;
vector<pair<int, int> > g[N];
void build(int i, int l, int r) {
if (l == r) {
tr[i] = 1e18;
return ;
}
int mid = (l + r) >> 1;
build(i * 2, l, mid);
build(i * 2 + 1, mid + 1, r);
tr[i] = 1e18;
}
void pushdown(int i, int l, int r, int mid) {
tr[i * 2] += lazy[i];
lazy[i * 2] += lazy[i];
tr[i * 2 + 1] += lazy[i];
lazy[i * 2 + 1] += lazy[i];
lazy[i] = 0;
}
void change(int i, int l, int r, int p) {
if (l == r) {
tr[i] = dp[p];
return ;
}
int mid = (l + r) >> 1;
if (mid >= p) {
change(i * 2, l, mid, p);
}
else change(i * 2 + 1, mid + 1, r, p);
tr[i] = min(tr[i * 2], tr[i * 2 + 1]);
}
void modify(int i, int l, int r, int x, int y, int z) {
if (x > y) {
return ;
}
if (l > y || r < x) {
return ;
}
if (l >= x && r <= y) {
tr[i] += z;
lazy[i] += z;
return ;
}
int mid = (l + r) >> 1;
pushdown(i, l, r, mid);
modify(i * 2, l, mid, x, y, z);
modify(i * 2 + 1, mid + 1, r, x, y, z);
tr[i] = min(tr[i * 2], tr[i * 2 + 1]);
}
int query(int i, int l, int r, int x, int y) {
if (x > y) {
return 1e18;
}
if (l > y || r < x) {
return 1e18;
}
if (l >= x && r <= y) {
return tr[i];
}
int mid = (l + r) >> 1;
pushdown(i, l, r, mid);
return min(query(i * 2, l, mid, x, y), query(i * 2 + 1, mid + 1, r, x, y));
}
signed main() {
cin >> n >> m;
for (int i = 1; i <= m; i++) {
cin >> l[i] >> r[i] >> a[i];
sum += a[i];
g[r[i]].push_back({l[i], a[i]});
}
build(1, 1, n);
for (int i = 1; i <= n + 1; i++) {
for (auto cur : g[i - 1]) {
tot += cur.second;
modify(1, 1, n, 1, cur.first - 1, cur.second);
}
dp[i] = min(tot, query(1, 1, n, 1, i - 1));
change(1, 1, n, i);
}
cout << max(0ll, sum - query(1, 1, n, 1, n));
return 0;
}
标签:return,int,void,tr,mid,20240816,dp
From: https://www.cnblogs.com/libohan/p/18428138