1,o(n)时间内算法
string getmin(string s) { int len=s.length(); s+=s; int i=0,j=1,k=0,t; while(i<len&&j<len&&k<len) { t=s[(i+k)%len]-s[(j+k)%len]; if(t==0) k++; else { if(t>0) i+=k+1; else j+=k+1; if(i==j) j++; k=0; } } string res=s.substr(min(i,j),len); return res; }
类似应用题
牛客-团结就是力量
团结就是力量(tarjan+字符串hash)-牛客
题意:给定n个字符串,和m对信息构成图,字符串经过变换后完全相等+两个点互相连通,可以一起出站,团结力:一起出站的最大人数
解:tarjan求最大连通分量,先将字符串预处理为字典序最小,最后离散化求最大值(连块+核对字符)
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+10; const int mod=142857; const int inf=0x3f3f3f3f; typedef long long ll; typedef pair<int,int> pii; string getmin(string s) { int len=s.length(); s+=s; int i=0,j=1,k=0,t; while(i<len&&j<len&&k<len) { t=s[(i+k)%len]-s[(j+k)%len]; if(t==0) k++; else { if(t>0) i+=k+1; else j+=k+1; if(i==j) j++; k=0; } } string res=s.substr(min(i,j),len); return res; } //强连通缩点 int dfn[maxn],low[maxn],tot; int Stack[maxn],vis[maxn],idx; int cnt;//连通分量的个数 int belong[maxn];//记录每个节点的强连通编号 vector<int> G[maxn*2]; string str[maxn]; int n,m,ans; void tarjan(int u) { dfn[u]=low[u]=++tot; vis[u]=1; Stack[++idx]=u; for(auto v:G[u]) { if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(vis[v]) { low[u]=min(low[u],dfn[v]); } } if(dfn[u]==low[u]) { cnt++; int k; map<string ,int> mp; do { k=Stack[idx--]; mp[str[k]]++;//对连通分量计数 vis[k]=0; }while(k!=u); for(auto it:mp) ans=max(ans,it.second); } } int main() { while(cin>>n>>m) { for(int i=1; i<=n; i++) G[i].clear(),dfn[i]=low[i]=vis[i]=0; tot=cnt=0; idx=ans=0; for(int i=1; i<=n; i++) { cin>>str[i]; str[i]=getmin(str[i]); //cout<<str[i]<<endl; } for(int i=0; i<m; i++) { int u,v; cin>>u>>v; G[u].push_back(v); } for(int i=1; i<=n; i++) { if(!dfn[i]) tarjan(i); } printf("%d\n",ans); } system("pause"); return 0; }