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

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值