CF1889C2 Doremy's Drying Plan (Hard Version) 题解
Description
有
Solution
一道比较好玩的 dp 题。建议评级紫。可能更好的观看体验。
单独考虑每个点。设现在在考虑点
如果我们按顺序考虑每个点是否不被覆盖,即在考虑
考虑
上面的分析中已经分析出了子问题结构,考虑 dp。设
这个方程直接转移是
首先如果覆盖在
容易发现当
假设有
这个序列将
动态 st 表可以做到
最后问题只剩下如何对于每个
利用差分思想。对每个位置维护两个集合
维护完
维护完
Code
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <set>
#include <cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
namespace SparseTable {
// bool bst;
int st[11][18][200005];
// bool bed;
int lg[200005];
int Init() {
lg[0] = -1;
for (int i = 1; i <= 200000; i ++)
lg[i] = lg[i >> 1] + 1;
return 0;
}
struct Table {
int tot = 0, z;
int clear() {
tot = 0, z = 0;
return 0;
}
int insert(int x) {
tot ++;
st[z][0][tot] = x;
int u = tot;
for (int i = 1; u - (1 << i) >= 0; i ++)
st[z][i][u] = (max(st[z][i - 1][u], st[z][i - 1][u - (1 << (i - 1))]));
return 0;
}
int query(int l, int r) {
l ++, r ++;
if (l > r) return -inf;
int len = lg[r - l + 1];
return max(st[z][len][r], st[z][len][l + (1 << len) - 1]);
}
};
}
namespace solve1 {
struct Node {
int a;
Node(int x) {
a = x;
}
};
bool operator<(Node a, Node b) {
return a.a > b.a;
}
int n, m, k;
using namespace SparseTable;
Table st[11];
pair<int, int> a[200005];
#define l(u) a[u].first
#define r(u) a[u].second
set<int> add[200005], del[200005];
set<Node> cover;
vector<int> cov[200005];
bool vis[200005];
int f[200005][11];
int clear() {
for (int i = 0; i <= 10; i ++)
st[i].clear(), st[i].z = i;
for (int i = 1; i <= n + 1; i ++)
cov[i].clear(), vis[i] = 0;
return 0;
}
int main() {
clear();
cin >> n >> m >> k;
for (int i = 1; i <= m; i ++)
cin >> l(i) >> r(i);
sort(a + 1, a + m + 1);
for (int i = 1; i <= m; i ++)
add[l(i)].insert(i), del[r(i) + 1].insert(i);
for (int i = 1; i <= n + 1; i ++) {
cov[i].push_back(i);
for (int j : del[i]) cover.erase(Node(j));
for (int j : add[i]) cover.insert(Node(j));
add[i].clear(), del[i].clear();
if (int(cover.size()) > k) vis[i] = 1;
int cnt = 0;
if (!vis[i] && (cover.size()))
for (Node j : cover) {
if (cnt == k) break;
cov[i].push_back(l(j.a)), cnt ++;
}
}
for (int i = 0; i <= k; i ++)
st[i].insert(0);
int ret = 0;
for (int i = 1; i <= n; i ++) {
if (vis[i]) {
for (int j = 0; j <= k; j ++)
st[j].insert(-inf), f[i][j] = -inf;
continue;
}
int tt = cov[i].size();
for (int j = 0; j < tt - 1; j ++)
f[i][j] = -inf;
for (int j = tt - 1; j <= k; j ++) {
f[i][j] = 0;
for (int p = 0; p < tt; p ++) {
if (p > j) break;
if (p != tt - 1)
f[i][j] = max(f[i][j], st[j - p].query(cov[i][p + 1], cov[i][p] - 1) + 1);
else
f[i][j] = max(f[i][j], st[j - p].query(0, cov[i][p] - 1) + 1);
}
}
for (int j = 0; j <= k; j ++)
st[j].insert(f[i][j]), ret = max(ret, f[i][j])/*, cout << i << " " << j << " " << f[i][j] << "\n"*/;
}
cout << ret << "\n";
return 0;
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
SparseTable::Init();
while (T --)
solve1::main();
return 0;
}