单词背诵
问题描述
灵梦有n个单词想要背,但她想通过一篇文章中的一段来记住这些单词。
文章由m个单词构成,她想在文章中找出连续的一段,其中包含最多的她想要背的单词(重复的只算一个)。并且在背诵的单词量尽量多的情况下,还要使选出的文章段落尽量短,这样她就可以用尽量短的时间学习尽可能多的单词了。
输入格式
第1行一个数n,接下来n行每行是一个长度不超过10的字符串,表示一个要背的单词。
接着是一个数m,然后是m行长度不超过10的字符串,每个表示文章中的一个单词。
输出格式
输出文件共2行。第1行为文章中最多包含的要背的单词数,第2行表示在文章中包含最多要背单词的最短的连续段的长度。
输入样例
3
hot
dog
milk
5
hot
dog
dog
milk
hot
输出样例
3
3
HINT
对于30%的数据 n<=50,m<=500;
对于60%的数据 n<=300,m<=5000;
对于100%的数据 n<=1000,m<=100000;
时间限制:1s
空间限制:128MB*/
鬼畜错误代码
#include<cstdio> #include<cstring> #include<iostream> #include<cstdlib> using namespace std; const int maxn=1e3+5; const int maxm=1e5+5; const int maxlen=20; const int N=1000007; int n,m,pre[maxm],first[N+5],next[maxn],ans=0,cnt[maxn];//cnt[i]琛ㄧず鍗曡瘝i鑳屼簡澶氬皯娆? bool visit[maxn]; char a[maxn][maxlen],b[maxm][maxlen]; inline int hash(char *ch){ int ans=0; int len=strlen(ch); for(int i=0;i<len;++i){ ans=(ans*31+ch[i]-'a')%N; } return ans%N; } inline bool same(char *a,char *b){ int la=strlen(a); int lb=strlen(b); if(la!=lb)return 0; for(register int i=0;i<la;++i){ if(a[i]!=b[i])return 0; } return 1; } inline void add(char *ch,int pos){ int key=hash(ch); for(int i=first[key];i;i=next[i]){ if( same( ch , a[i]) )return; } next[pos]=first[key]; first[key]=pos; } inline void find(char *ch,int pos){ int key=hash(ch); for(register int i=first[key];i;i=next[i]){ if( same( ch , a[i] ) ){ pre[pos]=i; if(!visit[i])ans++; visit[i]=1; } } } int main() { /*freopen("p386p.in","r",stdin); freopen("p386p.out","w",stdout);*/ scanf("%d",&n); gets(a[0]); for(register int i=1;i<=n;i++){ gets(a[i]); add(a[i],i); } scanf("%d",&m); gets(b[0]); for(register int i=1;i<=m;i++) { gets(b[i]); find(b[i],i); } printf("%d\n",ans); int kk=ans; ans=0x7fffffff; int right=0,left=0,temp=0; while(right<=m){ right++; if(!pre[right])continue; if(!cnt[ pre[right] ])temp++; cnt[ pre[right] ]++; while(left<=right && temp==kk){ ans=min(ans,right-left+1); if(cnt[ pre[left] ]==1)temp--; cnt[ pre[left] ]--; left++; } } printf("%d",ans); return 0; }
正确代码(内存操作错误 改正后)
/*问题描述
灵梦有n个单词想要背,但她想通过一篇文章中的一段来记住这些单词。
文章由m个单词构成,她想在文章中找出连续的一段,其中包含最多的她想要背的单词(重复的只算一个)。并且在背诵的单词量尽量多的情况下,还要使选出的文章段落尽量短,这样她就可以用尽量短的时间学习尽可能多的单词了。
输入格式
第1行一个数n,接下来n行每行是一个长度不超过10的字符串,表示一个要背的单词。
接着是一个数m,然后是m行长度不超过10的字符串,每个表示文章中的一个单词。
输出格式
输出文件共2行。第1行为文章中最多包含的要背的单词数,第2行表示在文章中包含最多要背单词的最短的连续段的长度。
输入样例 3 hot dog milk 5 hot dog dog milk hot 输出样例 3 3 HINT
对于30%的数据 n<=50,m<=500;
对于60%的数据 n<=300,m<=5000;
对于100%的数据 n<=1000,m<=100000;
时间限制:1s
空间限制:128MB*/
#include<cstdio> #include<cstring> #include<iostream> #include<cstdlib> #include<string> using namespace std; const int maxn=1e3+5; const int maxm=1e5+5; const int maxlen=20; const int N=10000003; int n,m,pre[maxm],first[N+5],next[maxn],ans=0,cnt[maxn]; bool visit[maxn]; string a[maxn]; string b[maxm]; inline int hash(string ch){ int ans=0; int len=ch.size(); for(int i=0;i<len;++i){ ans=(ans*31+ch[i]-'a')%N; } return ans%N; } inline bool same(string a,string b){ int la=a.size(); int lb=b.size(); if(la!=lb)return 0; for(register int i=0;i<la;++i){ if(a[i]!=b[i])return 0; } return 1; } inline void add(string ch,int pos){ int key=hash(ch); for(int i=first[key];i;i=next[i]){ if( same( ch , a[i]) )return; } next[pos]=first[key]; first[key]=pos; } inline void find(string ch,int pos){ int key=hash(ch); for(register int i=first[key];i;i=next[i]){ if( same( ch , a[i] ) ){ pre[pos]=i; if(!visit[i])ans++; visit[i]=1; } } } int main() { /*freopen("p386p.in","r",stdin); freopen("p386p.out","w",stdout);*/ scanf("%d",&n); for(register int i=1;i<=n;i++) { cin>>a[i]; add(a[i],i); } scanf("%d",&m); for(register int i=1;i<=m;i++) { cin>>b[i]; find(b[i],i); } printf("%d\n",ans); int kk=ans; ans=0x7fffffff; int right=0,left=0,temp=0; while(right<=m){ right++; if(!pre[right])continue; if(!cnt[ pre[right] ])temp++; cnt[ pre[right] ]++; while(left<=right && temp==kk){ ans=min(ans,right-left+1); if(cnt[ pre[left] ]==1)temp--; cnt[ pre[left] ]--; left++; } } printf("%d",ans); return 0; }