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