AtCoder Beginner Contest 260 Draw Your Cards

题面

有一副正面朝下的 N 张扑克牌,每张牌的正面数字构成一个1∼N 的全排列,从上到下的第 i 张牌数字为 p i p_i pi用这副牌,做 N 次操作,每次操作包含以下几步:
选择这幅牌最顶部的扑克牌,令该扑克牌上的数字为 X。
对于桌面上的正面朝上的扑克牌堆中,将该扑克牌放在所有顶部数字至少为 X 的牌堆中顶部数字最小的那堆的顶部。如果不存在这样的牌堆,将其正面朝上放在桌面上,构成一个新的牌堆。
接着,如果存在一个扑克牌数量为 K 的牌堆,将这堆牌移出桌面。
对于每张扑克牌,请你求出在第几次操作后被移出桌面,如果没有移出,输出 -1。输出时,第 i 行为带有数字 i 的对应扑克牌的答案。

题意

有n张卡片n此操作,如果当前朝上的牌堆中的顶面上没有大于当前这张卡片时,这张牌就单独一堆,否则就找到第一个大于当前牌的堆将这张牌放在这堆牌的最上面,当某堆牌的数量魏k时就移走这堆牌。问每一张牌是在第几次操作拿走了,询问顺顺序时1到n。

思路

模拟,用cnt数组记录每一堆牌的有多少张,to数组代表每张牌的下面那张牌是谁,再采用set记录每一堆牌的最上面是哪张,每次操作二分查找set里的值即可,ans记录答案。

代码

#include<bits/stdc++.h>

#define IOS ios::sync_with_stdio(false);cin.tie(nullptr)
#define int long long

using namespace std;

signed main()
{
	IOS;
	int n, k;
	cin >> n >> k;
	vector<int> v(n + 10), ans(n + 10, -1), cnt(n + 10), to(n + 10);
	//ans初始化-1有没有答案的牌
	for (int i = 0; i < n; i++) cin >> v[i];

	set<int> s;
	for (int i = 0; i < n; i++)
	{
		auto it = s.lower_bound(v[i]);//查找这一张牌应该放在哪一堆
		if (it == s.end())//如果没有找到相应的牌堆就是单独一堆
		{
			s.insert(v[i]);
			cnt[v[i]] = 1;//这一堆的大小当然为1
		}
		else
		{
			//如果找到了是哪一堆了那么这堆牌的顶面应该改变并且堆的大小+1
			cnt[v[i]] = cnt[*it] + 1;
			//更新一下这张牌的下面那张就是查找到的
			to[v[i]] = *it;
			//更改这堆牌的顶面大小
			s.erase(it);
			s.insert(v[i]);
		}
		if (cnt[v[i]] == k)
		{
			//记录这堆牌的操作数是是几
			for (int j = v[i]; j; j = to[j]) ans[j] = i + 1;
			s.erase(s.find(v[i]));
		}
	}
	for (int i = 1; i <= n; i++) cout << ans[i] << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值