好久都没写过日志了。。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 "); 54 else 55 printf("%d ",ans); 56 } 57 58 int main () 59 { 60 init(); 61 close(); 62 return 0; 63 }