题目链接
https://ac.nowcoder.com/acm/contest/7509/B
解题思路
我的思路:
pos记录属于puleyaknoi中字符的位置,pos_of_p_in_pos记录p在pos中的位置。
从pos_of_p_in_pos数组的最后一个p开始往后找字符串,按顺序puleyaknoi中的字符,若能找全,刷新ans。
大佬思路:
核心是用v[i]表示puleyaknoi中所有第i个字符的位置,是从小到大排序的,因为是从小到大push的。
枚举p的位置,作为区间左端点,字符串最右端作为右端点,check参数为i和二分的区间长度。
长度可行刷新ans,同时缩短区间。
我的AC代码
#include<bits/stdc++.h> using namespace std; const int N=1e5+100; char s[15]=".puleyaknoi"; int FindIDX(char ch){ for(int i=1;i<=10;i++) if(ch==s[i]) return i; return 0; } int main(){ int t; cin>>t; while(t--){ string str; cin>>str; int len=str.length(); str='.'+str; int pos[N],pos_of_p_in_pos[N]; int num=0,nump=0; for(int i=1;i<=len;i++){ int tmp=FindIDX(str[i]); if(tmp) pos[++num]=i; if(tmp==1) pos_of_p_in_pos[++nump]=num; } int ans=N; for(int i=nump;i>=1;i--){ int k=1,j=pos_of_p_in_pos[i]; for(;j<=num&&k<=10;j++){ if(str[pos[j]]==s[k]) k++; } if(k==11) ans=min(ans,pos[j-1]-pos[pos_of_p_in_pos[i]]+1); } if(ans>len) cout<<-1<<endl; else cout<<ans<<endl; /* cout<<"________________________________"<<endl; for(int i=1;i<=num;i++) cout<<pos[i]<<' '; cout<<endl; for(int i=1;i<=nump;i++) cout<<pos_of_p_in_pos[i]<<' '; cout<<endl; cout<<"________________________________"<<endl; */ } }
大佬AC代码
#include<bits/stdc++.h> using namespace std; const int N=1e6; vector<int> v[N]; int IS(char ch){ if(ch=='p') return 1; else if(ch=='u') return 2; else if(ch=='l') return 3; else if(ch=='e') return 4; else if(ch=='y') return 5; else if(ch=='a') return 6; else if(ch=='k') return 7; else if(ch=='n') return 8; else if(ch=='o') return 9; else if(ch=='i') return 10; return 0; } bool check(int p,int len){ int tmp=p; for(int i=2;i<=10;i++){ p=*lower_bound(v[i].begin(),v[i].end(),p);//不可以用upper_bound,因为假如p=N,那么p在下一次循环中的upper_bound中会被赋值成v中未知域的随机值。 #include<bits/stdc++.h> using namespace std; const int N=1e6; vector<int> v[N]; int IS(char ch){ if(ch=='p') return 1; else if(ch=='u') return 2; else if(ch=='l') return 3; else if(ch=='e') return 4; else if(ch=='y') return 5; else if(ch=='a') return 6; else if(ch=='k') return 7; else if(ch=='n') return 8; else if(ch=='o') return 9; else if(ch=='i') return 10; return 0; } int GetLenth(int p,int len){ int tmp=p; for(int i=2;i<=10;i++){ p=*lower_bound(v[i].begin(),v[i].end(),p); } if(p>tmp+len-1) return 0; else return p-tmp+1; } int main(){ int t; cin>>t; while(t--){ string str; for(int i=0;i<=10;i++) v[i].clear(); cin>>str; int len=str.length(); str='.'+str; for(int i=1;i<=len;i++){ v[IS(str[i])].push_back(i); } for(int i=1;i<=10;i++) v[i].push_back(N); int ans=N; for(int i=1;i<=len;i++){ if(str[i]=='p'){ int tmp=GetLenth(i,len-i+1); if(tmp) ans=min(ans,tmp); } } if(ans>=N) cout<<-1<<endl; else cout<<ans<<endl; } } } if(p>tmp+len-1) return false; else return true; } int main(){ int t; cin>>t; while(t--){ string str; for(int i=0;i<=10;i++) v[i].clear(); cin>>str; int len=str.length(); str='.'+str; for(int i=1;i<=len;i++){ v[IS(str[i])].push_back(i); } for(int i=1;i<=10;i++) v[i].push_back(N); int ans=N; for(int i=1;i<=len;i++){ if(str[i]=='p'){ int l=10,r=len-i+1; while(l<=r){//二分 int m=(l+r)>>1; if(check(i,m)) r=m-1,ans=min(ans,m); else l=m+1; } } } if(ans>=N) cout<<-1<<endl; else cout<<ans<<endl; } }
改编大佬代码后
我发现其实二分操作是多余的,只要用容器存好,利用lower_bound函数求出的就是最短的。
GetLenth参数为左端点为i,右端点始终为字符串右端点。
#include<bits/stdc++.h> using namespace std; const int N=1e6; vector<int> v[N]; int IS(char ch){ if(ch=='p') return 1; else if(ch=='u') return 2; else if(ch=='l') return 3; else if(ch=='e') return 4; else if(ch=='y') return 5; else if(ch=='a') return 6; else if(ch=='k') return 7; else if(ch=='n') return 8; else if(ch=='o') return 9; else if(ch=='i') return 10; return 0; } int GetLenth(int l,int r){ int tmp=l; for(int i=2;i<=10;i++){ l=*lower_bound(v[i].begin(),v[i].end(),l); } if(l>r) return 0; else return l-tmp+1; } int main(){ int t; cin>>t; while(t--){ string str; for(int i=0;i<=10;i++) v[i].clear(); cin>>str; int len=str.length(); str='.'+str; for(int i=1;i<=len;i++){ v[IS(str[i])].push_back(i); } for(int i=1;i<=10;i++) v[i].push_back(N); int ans=N; for(int i=1;i<=len;i++){ if(str[i]=='p' && len-i+1>=10){ int tmp=GetLenth(i,len); if(tmp) ans=min(ans,tmp); } } if(ans>=N) cout<<-1<<endl; else cout<<ans<<endl; } }