好久都没写过日志了。。TAT

描述 Description

给你一个长度为n的数字串,数字串里会包含1-m这些数字。如果连续的一段数字子串包含了1-m这些数字,则称这个数字字串为NUM串。你的任务是求出长度最短的NUM串是什么,只需要输出这个长度即可。
1<=n,m<=200000

输入格式 InputFormat

第一行给定n和m。 
第二行n个数,表示数字串,数字间用空格隔开。

输出格式 OutputFormat

如果存在NUM串则输出最短NUM串长度,否则输出“NO”。

样例输入 SampleInput [复制数据]

5 3
1 2 2 3 1

样例输出 SampleOutput [复制数据]

3

思路:扫一遍,用h,t表示头和尾指针。筛出里面的数,如果有<1或者>m的就不合法,清空h,t,此外,用一个f数组记录每个数用了多少次,这样的话,一个合法的数字串假设是1 1 2 3 3 3 4
那么我就知道一共出现的cnt=4,因为有F数组判重,这样的话,ans=min(ans,t-h+1);
2、找到一个合法的数字串后,尝试从h处往t处删数,并保证数字串的性质,这样不管怎么都是O(n)的,因为h始终在增大,并只操作一次,详见代码
 1 #include <cmath>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <string>
 6 #include <cstdlib>
 7 #include <map>
 8 using namespace std;
 9 
10 const int maxn=200010;
11 const int INF=101000000;
12 int a[maxn],b[maxn],f[maxn];
13 int cnt,ans,h,n,m,t;
14 
15 void close()
16 {
17 exit(0);
18 }
19 
20 
21 void init()
22 {
23     cnt=0;ans=INF;
24 
25     scanf("%d %d",&n,&m);
26     for (int i=1;i<=n;i++)
27         scanf("%d",&a[i]);
28     h=1;t=0;
29     while (t<n)
30     {
31         t++;
32         if (f[a[t]]==0)
33             cnt++;
34         f[a[t]]++;
35         if (a[t]>m || a[t]<1)
36         {
37             for (int j=h;j<=t;j++)
38                 f[a[j]]=0;
39             h=t+1;
40             cnt=0;
41         }
42         if (cnt==m)
43         {
44             while (f[a[h]]>=2)
45             {
46                 f[a[h]]--;
47                 h++;
48             }
49             ans=min(ans,t-h+1);
50         }
51     }
52     if (ans==INF)
53         printf("NO\n");
54     else
55         printf("%d\n",ans);
56 }
57 
58 int main ()
59 {
60     init();
61     close();
62     return 0;
63 }

 

posted on 2013-07-03 22:57  cssystem  阅读(503)  评论(0编辑  收藏  举报