codeforces Hello 2024(C和D) 蒟蒻补题

C题

首先是题干

这个题的大致意思就是在说:把一组数据分成两组,但必须按照原来的先后顺序,并且要使分出的这两组中的总的b[i]<b[i+1]的数量最小,下面是分析:

题干不是说要把这组数据分成两组吗?我们可以找两个盒子,这两个盒子刚开始有无限大的空间,然后向两第一个盒子中添加比它小的数,如果装着装着遇见了一个大数它装不下了,那我们可以将它换到下一个盒子,这样此时在第一个盒子中暂时不会出现b[i]<b[i+1],之后在循环往复的往里装,但在之后我们还会遇到一个数x比两个盒子里的数都大怎么办?我们可以将第一个盒子中的数换成第二个盒子中此时的数,并将第二个盒子中的数,改成这个 x,这样是不是相当于就给盒子进行了一次扩容,此时第一个盒子中是不是产生了第一个b[i]<b[i+1]?所以答案ans要加一。

至于为什么要把第一个盒子里的数改成当时第二个盒子里的数,因为x这个数超过了两个盒子,必须要让盒子进行扩容(也就是产生那个顺序对),在进行一次扩容后要想让总的顺序对最少,我们就要在每一次扩容后尽可能让盒子里的容量都变大一些,也就是将第一个盒子里的数变成第二个数,将第二个盒子的容量变成x。可能还会有为什么把第一个盒子里的数变成第二盒子的数就会使第一个盒子容量扩大的疑问,因为我们第一个盒子最先开始接受数据的数变得比第一个盒子容量大后才会装进第二个盒子,也就是说第二个盒子一定比第一个盒子大。

下面附上代码:

#include <iostream>

using namespace std;

int main()
{
	int t;
	cin >> t;

	while (t--)
	{
		int n;
		cin >> n;
		int a = 1e9, b = 1e9;
		int ans = 0;

		for (int i = 0; i < n; i++)
		{
			int x;
			cin >> x;

			if (a >= x) a = x;
			else if (b >= x) b = x;
			else a = b, b = x, ans++;
			
		}   
		cout << ans << endl;
	}
	return 0;
}

D题

题太长了就不贴了,这里就简单介绍下解法:

首先这是一个完全二叉树,并且一边的权重为1,另一边的权重就为0,所以两个叶结点的最小值就为他们的父节点到根节点的距离,然后每两个相邻的叶节点都进行如此的向上追朔,如果可以构成一株完全二叉树的话,那么最后回溯的终值应该为零。在一个数组a[N]中,我们也就是寻找a[prv[i]] == a[i] - 1 || a[nxt[i]] == a[i] - 1这样的点来进行操作,具体细节大家直接看代码吧:

#include <iostream>
#include <queue>

using namespace std;

const int N = 200005;

int n;
int a[N];
int prv[N];
int nxt[N];
bool in[N];

bool good(int i)
{
	if (i < 1 || i > n)
	{
		return 0;
	}
	return a[prv[i]] == a[i] - 1 || a[nxt[i]] == a[i] - 1;
}

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		cin >> n;
		priority_queue<pair<int, int>> pq;
		for (int i = 1; i <= n; i++)
		{
			prv[i] = i - 1;
			nxt[i] = i + 1;
			in[i] = 0;
			cin >> a[i];
		}

		a[n + 1] = a[0] = -2;

		for (int i = 1; i <= n; i++)
		{
			if (good(i))
			{
				in[i] = 1;
				pq.push({ a[i], i });
			}
		}

		while (!pq.empty())
		{
			auto item = pq.top();
			pq.pop();
			int i = item.second;
			nxt[prv[i]] = nxt[i];
			prv[nxt[i]] = prv[i];

			if (!in[prv[i]] && good(prv[i]))
			{
				in[prv[i]] = 1;
				pq.push({ a[prv[i]], prv[i] });
			}

			if (!in[nxt[i]] && good(nxt[i]))
			{
				in[nxt[i]] = 1;
				pq.push({ a[nxt[i]], nxt[i] });
			}
		}

		int mn = 1e9, bad = 0;
		for (int i = 1; i <= n; i++)
		{
			bad += !in[i];
			mn = min(a[i], mn);
		}
		if (bad == 1 && mn == 0)
		{
			cout << "Yes\n";
		}
		else
		{
			cout << "No\n";
		}
	}

	return 0;
}

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值