2020牛客寒假算法基础集训营6 C题

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;
}

嘻嘻我们下次见啦~武汉加油!武汉加油!武汉加油!重要的事情说三遍!!!

发布了53 篇原创文章 · 获赞 2 · 访问量 1368

猜你喜欢

转载自blog.csdn.net/qq_44624316/article/details/104348916