您的位置:首页 > 运维架构

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

2017-07-23 23:34 375 查看

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
,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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: