2020牛客寒假算法基础集训营6
C-汉诺塔
害=-=今天是2.16,是我知道自己宿舍被征用的一天,内心比较平静=-=写题写博客“宠辱不惊”,来吧~武汉加油!(武汉加油!中国加油!)
看到汉诺塔这个题目是不是直接想到了经典递归~
其实它不是=-=
是一道用二分优化dp方法,其中用到的方法相当于对栈的操作。
题目大概意思是给出n个木板的长和宽,按照汉诺塔的规则,从小到大依次摆放,要求从小到大是严格递增的顺序,问最少需要几组才成完成摆放。
这个地方用到了Dilworth定理(狄尔沃斯定理):
在一个序列中,最长下降子序列的个数(是不是就是我们要求的最少需要多少组)就是等于其不下降子序列的长度,反过来也一样呀~
解题思路:我们把木板的x从小到大排列。用二分的方法优化出当前木板所处的组数,像一个栈一样(这个栈存储木板的y),更新当前栈顶的y值,组别相应的发生变换即可。
这里列出二分的过程:
while (l <= r)
{
int mid = (l + r) >> 1;
if (s[mid] < a[i].y)
{
r = mid - 1;
}
else
{
l = mid + 1;
}
}
如果当前操作的木板y值大于二分出来的y值,那么还不是最优位置,
r = mid - 1,否则就是l = mid + 1
这里的s[]是状态数组。相当于栈=-=(我前面说的)
下面的代买是更新状态数组的值(相当于栈顶的更新)
更新组别
然后记录当前操作木板的组别(存在数组里面即可)
s[l] = a[i].y;
if (l > m)
{
m = l;
}
ans[a[i].loc] = l;
好啦上代码啦~
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
struct node
{
int x, y, loc;
}a[N];
bool cmp(node a, node b)
{
return a.x < b.x;
}
int n, m;
int s[N];
int ans[N];
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
scanf ("%d%d", &a[i].x, &a[i].y);
a[i].loc = i;
}
sort(a + 1, a + n + 1, cmp);
for (int i = 1; i <= n; i++)
{
int l = 1, r = m;
while (l <= r)
{
int mid = (l + r) >> 1;
if (s[mid] < a[i].y)
{
r = mid - 1;
}
else
{
l = mid + 1;
}
}
s[l] = a[i].y;
if (l > m)
{
m = l;
}
ans[a[i].loc] = l;
}
cout << m << endl;
for (int i = 1; i <= n; i++)
{
cout << ans[i] << " ";
}
cout << endl;
return 0;
}
嘻嘻我们下次见啦~武汉加油!武汉加油!武汉加油!重要的事情说三遍!!!