AT_wtf22_day1_d Welcome to Tokyo! 题解
非常有意思的题目。
思路#
考虑如何统计答案。
我们设
那么有:
这是一个线性规划形式,虽然我感觉初看原题的时候很难想到要写成这样的线性规划形式。
我们要统计的是:
整理一下:
由于原问题并不是很好做,我们可以想到线性规划对偶来看一看。
可以对限制加上一些乘子变量放到式子中。
然后以
依据
整理一下。
容易发现
而使用
那么问题又简化成:
它的意义是什么。
我们需要挑选出一个最大的线段集,使得每个点被覆盖的次数小于等于
不妨设答案为
其中,
并且又有结论是必定会有
使用线段树模拟即可。
时间复杂度:
Code#
/*
! 如果没有天赋,那就一直重复
! Created: 2024/06/26 15:23:52
*/
#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
#define fro(i, x, y) for (int i = (x); i <= (y); i++)
#define pre(i, x, y) for (int i = (x); i >= (y); i--)
const int N = 1e6 + 10;
int n, m, l[N], r[N], d[N], w[N], s[N];
int v[N << 1];
int g[N << 1];
list<int> t[N << 1];
inline void upd(int p, int l, int r, int k, int x) {
t[p].push_back(x);
if (l == r) return;
int mid = (l + r) >> 1;
if (mid >= k) upd(mid<<1, l, mid, k, x);
if (mid < k) upd(mid<<1|1, mid + 1, r, k, x);
}
inline void ckm(int&x, int y) {
if (x == 0) x = y; else if (y && r[x] > r[y]) x = y;
}
inline void pdo(int p, int mid) {
if (g[p]) {
g[mid<<1] += g[p], g[mid<<1|1] += g[p];
v[mid<<1] += g[p], v[mid<<1|1] += g[p];
g[p] = 0;
}
}
inline void add(int p, int l, int r, int L, int R) {
if (L <= l && r <= R) return g[p]++, v[p]++, void();
int mid = (l + r) >> 1; pdo(p, mid);
if (mid >= L) add(mid<<1, l, mid, L, R);
if (mid < R) add(mid<<1|1, mid + 1, r, L, R);
v[p] = max(v[mid<<1], v[mid<<1|1]);
}
inline int ask(int p, int l, int r, int L, int R) {
while (t[p].empty() == 0 && w[t[p].front()]) t[p].pop_front();
if (t[p].empty()) return 0;
if (L <= l && r <= R) return t[p].front();
int mid = (l + r) >> 1, num = 0;
if (mid >= L) ckm(num, ask(mid<<1, l, mid, L, R));
if (mid < R) ckm(num, ask(mid<<1|1, mid + 1, r, L, R));
return num;
}
inline int ask(int p, int l, int r, int k) {
if (l == r) return l;
int mid = (l + r) >> 1; pdo(p, mid);
return v[mid<<1|1] == k ? ask(mid<<1|1, mid + 1, r, k) : ask(mid<<1, l, mid, k);
}
inline int get(int i, int j) {
return m - s[i] + j * i;
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m;
fro(i, 1, m) {
cin >> l[i] >> r[i];
}
iota(d + 1, d + m + 1, 1);
sort(d + 1, d + m + 1, [&](int x, int y) {
return r[x] < r[y];
});
fro(i, 1, m) upd(1, 1, n, l[d[i]], d[i]);
fro(i, 1, m) {
s[i] = s[i - 1];
if (s[i] != m) {
int las = 1;
while (s[i] < m && las <= n) {
int x = ask(1, 1, n, las, n);
if (x == 0) break;
w[x] = 1, s[i]++, add(1, 1, n, l[x], r[x]);
if (v[1] == i) las = ask(1, 1, n, i) + 1;
}
}
}
int it = m;
fro(i, 1, n) {
while (it && get(it, i) > get(it - 1, i)) it--;
cout << get(it, i) << "\n";
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)