2020牛客寒假算法基础集训营6.C——汉诺塔贪心 & Dilworth定理 & 二分求上升子序列最小化分数

不飞则已,一飞冲天;不鸣则已,一鸣惊人。这篇文章主要讲述2020牛客寒假算法基础集训营6.C——汉诺塔贪心 & Dilworth定理 & 二分求上升子序列最小化分数相关的知识,希望能为你提供帮助。


??题目传送门??
题目描述
现在你有 N 块矩形木板,第 i 块木板的尺寸是 Xi*Yi,你想用这些木板来玩汉诺塔的游戏。
我们知道玩汉诺塔游戏需要把若干木板按照上小下大的顺序堆叠在一起,但因为木板是矩形,所以有一个问题:
第 i 块木板能放在第 j 块木板上方当且仅当 Xi< Xj 且 Yi< Yj,于是你很可能没法把所有的木板按照一定的次序叠放起来。
你想把这些木板分为尽可能少的组,使得每组内的木板都能按照一定的次序叠放。
你需要给出任意一种合理的分组方案。
提醒:“任意”意味着你的答案不必和标准输出完全一致,只要正确即可。
输入描述:
第一行,一个正整数 N
接下来 N 行,每行两个正整数表示 Xi 和 Yi
对于所有的数据,1≤N≤100,000,1≤Xi,Yi≤N,Xi 互不相等且 Yi 互不相等
输出描述:
输出文件包含两行,第一行一个正整数,表示最少组数
第二行 N 个正整数,依次表示你的方案中每块木板分在了哪一组
组的编号必须是从 1 开始的连续整数
输入

3
1 1
2 3
3 2
输出
【2020牛客寒假算法基础集训营6.C——汉诺塔贪心 & Dilworth定理 & 二分求上升子序列最小化分数】2
1 1 2
题解
  • 首先按照从小到达排序,则问题转化为
  • 由Dilworth定理:
  • 那么我们就可以求
  • 然后就变成了板子题了,细节见代码注释
AC-Code
#include < bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 7;

struct Node
int x, y, id;
bool operator < (const Node& t)const
return x < t.x;

a[maxn];
int ans[maxn]; // 组号
int st[maxn]; // 记录长度为i的下降子序列末尾元素(相同长度记录大的)
int main()
int n; while (cin > > n)
for (int i = 1; i < = n; ++i)
cin > > a[i].x > > a[i].y;
a[i].id = i;

sort(a + 1, a + 1 + n); // 按照x升序排序
int m = 0; // 记录最长下降子序列长度(Dilworth定理:=上升子序列最小划分数)
for (int i = 1; i < = n; ++i)
int l = 1, r = m; // 二分查找范围
while (l < = r)
int mid = (l + r) > > 1; // 题目没有相等情况
if (a[i].y > st[mid])r = mid - 1;
elsel = mid + 1;

st[l] = a[i].y;
if (l > m)m = l; // 更新最长下降子序列长度
ans[a[i].id] = l;

cout < < m < < endl;
for (int i = 1; i < = n; ++i)cout < < ans[i] < < " ";





    推荐阅读