BZOJ 3377 [Usaco2004 Open]The Cow Lineup 奶牛序列

来源:互联网 发布:宝日龙梅 知乎 编辑:程序博客网 时间:2024/05/18 20:52

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

Sample Output

3
样例说明
所有的长度为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;}

阅读全文
0 0
原创粉丝点击