题意:给你一个字符串,进行q次询问操作,每次给你一个n和一个子串,问能否在字符串中出现n次子串,若可以输出最短长度的n次子串,否则输出-1
题解:优雅的暴力哈希,枚举每一个不同种长度的子串,注意是不同种!因为这样子能减少枚举的次数,这是一个巨大的优化,同时用unordered_map这个不按key排序的map,减少logn的STL复杂度。(我就说一定存在不按照key排序的map啊啊啊)
还是我很挫的代码
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <map> #include <unordered_map> #include <queue> #include <vector> #include <cstring> #include <iomanip> #include <set> #include<ctime> //CLOCKS_PER_SEC #define se second #define fi first #define ll long long #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define Pii pair<int,int> #define Pli pair<ll,int> #define ull unsigned long long #define pb push_back #define fio ios::sync_with_stdio(false);cin.tie(0) const int N=1e5+5; const ull base=131; const int INF=0x3f3f3f3f; using namespace std; ull Hash[N]; ull p[N]; unordered_map<ull,int>mp; ull get(int l,int r){ if(l==0)return Hash[r]; return Hash[r]-Hash[l-1]*p[r-l+1]; } int L[N],id[N],a[N]; ull H[N]; bool cmp(int x,int y){ return L[x]<L[y]; } vector<int>ans[N]; int main(){ fio; string str; cin>>str; int len=str.length(); Hash[0]=str[0]; p[0]=1; for(int i=1;i<len;i++){ Hash[i]=Hash[i-1]*base+str[i]; p[i]=p[i-1]*base; } int n; cin>>n; for(int i=1;i<=n;i++){ string op; cin>>a[i]; cin>>op; id[i]=i,L[i]=op.length(); ull u=0; for(int j=0;j<L[i];j++){ u=u*base+op[j]; } H[i]=u; mp[H[i]]=i; } sort(id+1,id+1+n,cmp); for(int i=1,oo=1;i<=n;i+=oo){ oo=1; while(L[id[oo+i]]==L[id[i]])oo++; int pp=id[i]; for(int j=0;j+L[pp]<=len;j++){ ull m=get(j,j+L[pp]-1); if(mp.find(m)!=mp.end()){ ans[mp[m]].pb(j); } } } for(int i=1;i<=n;i++){ if(ans[i].size()<a[i])cout<<-1<<endl; else{ int MIN=INF; for(int j=a[i]-1;j<ans[i].size();j++){ MIN=min(MIN,ans[i][j]-ans[i][j-a[i]+1]+L[i]); } cout<<MIN<<endl; } } return 0; }