1. 程式人生 > 其它 >P5093 [USACO04OPEN]The Cow Lineup 題解

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