P5341 [TJOI2019]甲苯先生和大中鋒的字串 題解
阿新 • • 發佈:2022-05-18
拿出出現次數為 \(k\) 的點,給這個點表示的長度區間 \(+1\),這個可以使用差分解決。
點選檢視程式碼
const int N=1e5+13; char s[N]; int nxt[N<<1],len[N<<1],ptot,lastpos,ind[N<<1]; ll cnt[N<<1],a[N]; std::unordered_map<int,int> son[N<<1],boom; inline int newpos(std::unordered_map<int,int> nson,int nlen){return len[++ptot]=nlen,std::swap(son[ptot],nson),ptot;} inline void insert(int c){ int p=lastpos;int u=newpos(boom,len[p]+1);cnt[u]=1; while(p&&son[p].find(c)==son[p].end()) son[p][c]=u,p=nxt[p]; lastpos=u; if(!p) return nxt[u]=1,void(); int d=son[p][c]; if(len[d]==len[p]+1) nxt[u]=d; else{ int v=newpos(son[d],len[p]+1);cnt[v]=0; nxt[v]=nxt[d],nxt[d]=nxt[u]=v; while(p&&son[p][c]==d) son[p][c]=v,p=nxt[p]; } } inline void clear(){ ptot=lastpos=1; memset(a,0,sizeof a);memset(ind,0,sizeof ind); std::unordered_map<int,int> zrzak;std::swap(zrzak,son[1]); } int main(){int T;read(T);while(T--){ clear(); read(s+1);int n=strlen(s+1),k; read(k); for(int i=1;i<=n;++i) insert(s[i]-'a'); for(int i=2;i<=ptot;++i) ind[nxt[i]]++; std::queue<int> q; for(int i=2;i<=ptot;++i) if(!ind[i]) q.push(i); while(!q.empty()){ int u=q.front();q.pop(); if(nxt[u]==1) continue; cnt[nxt[u]]+=cnt[u]; if(!(--ind[nxt[u]])) q.push(nxt[u]); } for(int i=2;i<=ptot;++i) if(cnt[i]==k) a[len[nxt[i]]+1]++,a[len[i]+1]--; int ans=-1,maxx=1; for(int i=1;i<=n;++i){ a[i]+=a[i-1]; if(a[i]>=maxx) maxx=a[i],ans=i; } println(ans); } return 0; }