Description
约翰的N(1≤N≤100000)只奶牛站成了一列.每只奶牛都写有一个号牌,表示她的品种,号牌上的号码在1…K(1≤K≤10000)范围内.比如有这样一个队列
1,5,3,2,5,3,4,4,2,5,1,2,3
根据约翰敏锐的数学神经,他发现一些子序列在这个队列里出现,比如3,4,1,3,而另一些没有.子序列的各项之间穿插有其他数,也可认为这个子序列存在, 现在,他想找出一个最短的子序列(由1..K组成),使之不在奶牛序列里出现.达个子序列的长度是多少呢?
Input
第1行输入两个整数N和K,接下来N行输入奶牛序列.
Output
最短的不出现子序列.
Sample Input
14 5
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
Sample Output
3
样例说明
所有的长度为1和为2的子序列都出现.长度为3的序列“2,2,4”不出现
样例说明
所有的长度为1和为2的子序列都出现.长度为3的序列“2,2,4”不出现
HINT
Source
感觉很冷门啊这题。。
一开始感觉头昏脑胀……
修了好几天仙了,思考的力气都不大有。
后来发现网上这题甚至都没什么题解= =,,灵光一闪有了思路,就来写个题解。。
考虑长度为2的排列的情况,我们知道,
假如说在L~p的位置出现了1~K(可以多次出现),而在
q~R的位置也出现了1~K(可以多次出现),
其中q>p,
那么必定2的排列都齐了。两两配对嘛。
所以一个长度为len的排列全部到齐的条件是,存在len个不交叉的1~K的段,
不交叉的意思就是没有相同覆盖的地方。
这个很好理解吧……
然后就是如何实现的问题了。
首先一种思路就是不断累加直到K个都有了,然后标记数组清零,答案+1.
问题就是标记数组清零很耗时间,相当于一个for循环。。
还是用到以前用过的,所谓粗略标记永久化的东西:
用一个变量tmp,每次标记成tmp,然后当需要清零时,只需要更改tmp即可。
这里我的代码里面简洁化了,直接标记成正在累计的ans……
#include<bits/stdc++.h>
using namespace std;
int read(){
int x=0,f=1;char ch=getchar();
while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int
N=100005,
K=10005;
int n,k,a[N],f[K];
int main(){
n=read(),k=read();
for (int i=1;i<=n;i++) a[i]=read();
int ans=0,t=0;
memset(f,255,sizeof(f));
for (int i=1;i<=n;i++)
if (f[a[i]]!=ans){
f[a[i]]=ans;
if (++t==k) ans++,t=0;
}
printf("%d\n",ans+1);
return 0;
}