题意:有n页书,每页有个编号为ci的知识点,求最小看连续的页数,其中包括所有的知识点
分析:n<=1e6,只能搞O(n)的解法,无非就是枚举起点和终点,尺取法正好适合这个想法,枚举一个起点,然后往后扫描到区间内包括所有的知识点,然后每次起点都往右移动一次,直到扫描到右边界也没有答案了,就跳出
程序跑了469ms,应该是map太慢,可以hash搞一波,也过了,但是可以离散化知识点的编号,最多有1e6个,空间换时间
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<map> using namespace std; const int maxn=1e6+5; int c[maxn]; map<int,int> v; int main(){ int n; while(~scanf("%d",&n)){ v.clear(); int count=0; for(int i=0;i<n;i++){ scanf("%d",c+i); if(v[c[i]]==0){ v[c[i]]=1; count++; } } int ans=n+1;int cnt=0,l=0,r=0; v.clear(); for(;;){ while(r<n&&cnt<count){ if(v[c[r]]==0)cnt++; v[c[r++]]++; } if(cnt<count)break; ans=min(ans,r-l); if(v[c[l]]==1)cnt--; v[c[l++]]--; } printf("%d ",ans); } return 0; }
hash,跑了250ms,速度提升了一半
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<map> #include<cstring> using namespace std; const int maxn=1e6+5; int c[maxn],v[maxn]; inline int hash(int x){ return x%699997; } int main(){ int n; while(~scanf("%d",&n)){ memset(v,0,sizeof(v)); int count=0; for(int i=0;i<n;i++){ scanf("%d",c+i); if(v[hash(c[i])]==0){ v[hash(c[i])]=1; count++; } } int ans=n+1;int cnt=0,l=0,r=0; memset(v,0,sizeof(v)); for(;;){ while(r<n&&cnt<count){ if(v[hash(c[r])]==0)cnt++; v[hash(c[r++])]++; } if(cnt<count)break; ans=min(ans,r-l); if(v[hash(c[l])]==1)cnt--; v[hash(c[l++])]--; } printf("%d ",ans); } return 0; }