P5093 [USACO04OPEN]The Cow Lineup 题解

这道题是一道思维题。

定义『段』如下:

  • 段:一个段是原序列的连续子序列,其中 \([1,k]\) 内的所有正整数都出现过。

据此,我们可以对原序列分段,分的尽量多。

比如样例:

1 5 3 2 5 1 3 4 4 2 5 1 2 3

可以将其分成下面两段:

[1 5 3 2 5 1 3 4][4 2 5 1 2 3]

我们发现,每一次取每一段的最后一个数字,然后后面在加一个数字就可以构造出要求的子序列。

所以,答案就是段数+1。


Code:

/*
========= Plozia =========
	Author:Plozia
	Problem:P5093 [USACO04OPEN]The Cow Lineup
	Date:2021/6/7
========= Plozia =========
*/

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int MAXN = 1e5 + 5, MAXK = 1e4 + 5;
int n, k, a[MAXN], ans = 1;
queue <int> q[MAXK];

int Read()
{
	int sum = 0, fh = 1; char ch = getchar();
	for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1;
	for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = sum * 10 + ch - '0';
	return sum * fh; 
}
int Max(int fir, int sec) { return (fir > sec) ? fir : sec; }

int main()
{
	n = Read(), k = Read();
	for (int i = 1; i <= n; ++i) a[i] = Read();
	for (int i = 1; i <= n; ++i) q[a[i]].push(i);
	sort(a + 1, a + n + 1);
	int cntn = unique(a + 1, a + n + 1) - (a + 1);
//	/*Debug*/printf("%d\n", cntn);
	for (int pos = 0; ; ++ans)
	{
		bool flag = 0;
		for (int i = 1; i <= k; ++i)
		{
			while (!q[i].empty() && q[i].front() <= pos) q[i].pop();
			if (q[i].empty()) { flag = 1; break ; }
		}
		if (flag == 1) break ;
		for (int i = 1; i <= k; ++i)
		{
			pos = Max(pos, q[i].front());
		}
	}
	printf("%d\n", ans);
	return 0;
}
posted @ 2022-04-17 16:18  Plozia  阅读(24)  评论(0编辑  收藏  举报