P2652 同花顺

P2652 同花顺

Link

题目背景

所谓同花顺,就是指一些扑克牌,它们花色相同,并且数字连续。

题目描述

现在我手里有 (n) 张扑克牌,但它们可能并不能凑成同花顺。我现在想知道,最少更换其中的多少张牌,我能让这 (n) 张牌都凑成同花顺?

输入格式

第一行一个整数 (n) ,表示扑克牌的张数。

接下来 (n) 行,每行两个整数 (a_{i})(b_{i}) . 其中 (a_{i}) 表示第 (i) 张牌的花色,(b_{i}) 表示第 (i) 张牌的数字。

输出格式

一行一个整数,表示最少更换多少张牌可以达到目标。

输入输出样例

输入 #1

5
1 1
1 2
1 3
1 4
1 5

输出 #1

0

输入 #2

5
1 9
1 10
2 11
2 12
2 13

输出 #2

2

说明/提示

  • 对于 30% 的数据,(n le 10)

  • 对于 60% 的数据,(n le 10^{5})(1 le a_{i} le 10^{5})(1 le b_{i} le n)

  • 对于 100% 的数据,(n le 10^{5})(1 le a_{i}, b_{i} le 10^{9})

前言

这道题好ex,考试考了好几次了都没写出来(怪自己太菜了)。


题解

首先呢,这道题有一个比较特殊的性质,就是重复的牌一定会被我们替换掉,这就以意味着我们需要对牌进行去重。

我们可以转化一下问题,求一下最长的符合同花顺序列的长度,这样就比较好求了。

我们最后的答案就是 原来的牌数减去最长的符合同花顺序列的长度。

假设,我们以这张牌作为当前同花顺序列的最后一张牌,那么前面的那几张牌的数字都是要 大于当前的牌的数字减 (n)

所以我们可以对牌按花色排序,如果花色相同按牌的数字排序。

我们开个队列存当前的同花顺序列,如果当前的牌 (i) 与之前的牌的花色都不同,就把整个队列清空。

反之,枚举左端点,找到第一个与他花色不同或者数字比他小 (n) 的牌 (j),同花顺序列的长度就是 (i-j)

可以考虑用一个队列来优化一下:

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 1e5+10;
int n,cnt,ans,tot;
queue<int> que;
inline int read()
{
	int s = 0,w = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9'){s =s * 10+ch - '0'; ch = getchar();}
	return s * w;
}
struct node
{
	int c,num;
}q[N],a[N];
bool comp(node a,node b)//按花色排序,花色相同按数字排序
{
	if(a.c == b.c) return a.num < b.num;
	else return a.c < b.c;
}
int main()
{
//	freopen("card.in","r",stdin);
//	freopen("card.out","w",stdout);
	n = read();
	for(int i = 1; i <= n; i++)
	{
		q[i].c = read();
		q[i].num = read();
	}
	sort(q+1,q+n+1,comp);
	for(int i = 1; i <= n; i++)//去重
	{
		if(q[i].c == q[i-1].c && q[i].num == q[i-1].num) continue;
		else a[++tot] = q[i];
	}
	for(int i = 1; i <= tot; i++)
	{
		if(a[i].c != a[i-1].c)//与之前花色不同,把队列清空
		{
			while(!que.empty()) que.pop();
		}
		while(que.size() && a[que.front()].num < a[i].num - n) que.pop();//去掉数字比他小n的点
		que.push(i);
		ans = max(ans,(int) que.size()); //更新一下最长同花顺序列的长度
	}
	printf("%d
",n - ans);
	fclose(stdin); fclose(stdout);
	return 0;
}

原文地址:https://www.cnblogs.com/genshy/p/13662644.html