Living-Dream 系列笔记 第58期
T1
第一问开桶统计即可。
第二问我们采用双指针,不断地移动 \(r\) 直到包下含有最多单词数的区间,再移动 \(l\) 使答案更优并不断更新答案即可。
具体有一些细节见代码。时间复杂度 \(O(n \log n)\)。
可以把代码中的两个 map 换成数组存 hash value,时间可以降至 \(O(n)\),但是我懒了。()
code
#include<bits/stdc++.h> using namespace std; const int N=1e3+5,M=1e5+5; int n,m,ans1,ans2=1e9; map<string,int> vis,cnt; string a[N],b[M]; int main(){ cin>>n; for(int i=1;i<=n;i++) cin>>a[i],vis[a[i]]=1; cin>>m; for(int i=1;i<=m;i++){ cin>>b[i]; if(vis[b[i]]==1) ans1++,vis[b[i]]++; } if(ans1==0) cout<<0<<'\n'<<0,exit(0); int l=1,r=0,tot=0; while(r<m){ while(tot<ans1&&r<m){ cnt[b[++r]]++; if(cnt[b[r]]==1&&vis[b[r]]) tot++; } while(tot==ans1){ ans2=min(ans2,r-l+1); cnt[b[l]]--; if(!cnt[b[l]]&&vis[b[l]]) tot--; l++; } } cout<<ans1<<'\n'<<ans2; return 0; }
T2
很容易(?)发现一个性质:一个反对称字符串,去掉它两头的若干个字符,剩下的字符串仍是反对称的。
这启发我们不是去枚举子串,而是去枚举字串的对称轴。
其中对称轴一定位于两个字符之间,因为子串长度必定为偶数(是奇数则中间那个数会被取反,导致整个子串不可能反对称)。
接下来,我们二分子串长度的一半,然后比较子串的 hash value 与 它反对称后的 hash value 是否相等即可完成 check(这两个都可以预处理出来)。
然后对于每个反对称字串,根据我们发现的性质可得,它对答案的贡献即为 \(\frac{len}{2}\)(因为它两头去掉偶数个字符后仍为反对称字符串)。
code
#include<bits/stdc++.h> #define ull unsigned long long #define i64 long long using namespace std; const int N=5e5+5; const int BASE=13331; i64 n,ans; string s; ull hs[N],ht[N],p[N]; void init_hash(){ p[0]=1; for(int i=1;i<=n;i++) hs[i]=hs[i-1]*BASE+s[i],p[i]=p[i-1]*BASE; for(int i=1;i<=n;i++) s[i]=(s[i]=='0'?'1':'0'); for(int i=n;i>=1;i--) ht[i]=ht[i+1]*BASE+s[i]; } int get_hs(int l,int r){ return hs[r]-hs[l-1]*p[r-l+1]; } int get_ht(int l,int r){ return ht[l]-ht[r+1]*p[r-l+1]; } bool check(int now,int x){ int ll=now-x/2+1,rr=now+x/2; return get_hs(ll,rr)==get_ht(ll,rr); } int main(){ cin>>n>>s,s='#'+s; init_hash(); for(int i=1;i<n;i++){ int l=0,r=min((i64)i,n-i)*2+1; while(l+1<r){ int mid=(l+r)>>1; if(check(i,mid)) l=mid; else r=mid; } ans+=l/2; } cout<<ans; return 0; }
作业 T1
当然你可以用 map 水过,但是这里我们用 hash。
直接预处理每篇文章里每个单词的 hash value,然后对于每个询问,求出当前单词的 hash value 再一一比对即可。
map code
#include<bits/stdc++.h> using namespace std; int n,m,l; map< string,set<int> > ms; set<int>::iterator it; int main(){ cin.tie(nullptr); cout.tie(nullptr); cin>>n; for(int i=1;i<=n;i++){ cin>>l; for(int k=1;k<=l;k++){ string tmp; cin>>tmp; ms[tmp].insert(i); } } cin>>m; for(int i=1;i<=m;i++){ string tmp; cin>>tmp; if(ms.count(tmp)) for(it=ms[tmp].begin();it!=ms[tmp].end();it++) cout<<*it<<' '; cout<<'\n'; } return 0; }
hash code
#include<bits/stdc++.h> #define ull unsigned long long using namespace std; const int N=5e3+5,M=1e3+5; const int BASE=13331; int n,m,l[N]; string s[N][M]; ull hs[N][M]; void init_hash(int i,int j){ for(int k=0;k<s[i][j].size();k++) hs[i][j]=hs[i][j]*BASE+s[i][j][k]; } int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>l[i]; for(int j=1;j<=l[i];j++) cin>>s[i][j],init_hash(i,j); } cin>>m; for(int i=1;i<=m;i++){ string ss; cin>>ss; ull ss_hash=0; for(int j=0;j<ss.size();j++) ss_hash=ss_hash*BASE+ss[j]; for(int j=1;j<=n;j++){ for(int k=1;k<=l[j];k++){ if(ss_hash==hs[j][k]){ cout<<j<<' '; break; } } } cout<<'\n'; } return 0; }
作业 T2
二分最后的匹配成功的位置,截取 \(A,B\) 串相应区间比对完成 check,最后用桶统计答案即可。
具体细节见代码。
code
#include<bits/stdc++.h> #define ull unsigned long long using namespace std; const int N=2e5+5; const int BASE=13331; int n,m,q,ans[N]; string a,b; ull hsa[N],hsb[N],p[N]; void init_hash(){ p[0]=1; for(int i=1;i<=n;i++) hsa[i]=hsa[i-1]*BASE+a[i],p[i]=p[i-1]*BASE; for(int i=1;i<=m;i++) hsb[i]=hsb[i-1]*BASE+b[i]; } ull get_hsa(int l,int r){ return hsa[r]-hsa[l-1]*p[r-l+1]; } ull get_hsb(int l,int r){ return hsb[r]-hsb[l-1]*p[r-l+1]; } int main(){ cin>>n>>m>>q>>a>>b; a='#'+a,b='#'+b; init_hash(); for(int i=1;i<=n;i++){ int l=0,r=min(n-i+1,m)+1; while(l+1<r){ int mid=(l+r)>>1; if(get_hsa(i,mid+i-1)==get_hsb(1,mid)) l=mid; else r=mid; } ans[l]++; } while(q--){ int x; cin>>x,cout<<ans[x]<<'\n'; } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现