题目
(n le 10^{18} , |T| le 10^5)
题解
-
显然,最少的操作次数一定是贪心地能匹配就匹配
-
我们可以建出(T)的SAM,把SAM不能走的边补到根的后继节点
-
问题变成在SAM上设计一条长度为(n)的路径使得它绕回根的次数最多
-
由于字符集为4,并且我们只关心绕回根的次数
-
可以在SAM上dp预处理一个(4 imes 4)的矩阵表示从(x)开头经过根到(y)开头的最小长度
-
二分答案,矩阵快速幂check
-
考场没有想到二分,直接搜索了一下ABCD的顺序然后重复走中间的环,水过去了。。
#include<bits/stdc++.h> #define ll long long #define inf 1e9 using namespace std; const int N=200010; int l,cnt,ch[N][4],fa[N],len[N],d[N],a[10],used[N]; char s[N]; ll n,ans=1,f[N],dis[4][4]; void chkmn(ll&x,ll y){if(x>y)x=y;} void chkmx(ll&x,ll y){if(x<y)x=y;} void pre_dfs(int u){ if(used[u])return; used[u]=1; for(int i=0;i<4;++i){ int v=ch[u][i]; if(!v)continue; d[v]++; pre_dfs(v); } } void get_dis(int I){ static queue<int>q; q.push(ch[1][I]); f[ch[1][I]]=1; while(!q.empty()){ int u=q.front();q.pop(); for(int i=0;i<4;++i){ int v=ch[u][i]; if(!v){chkmn(dis[I][i],f[u]);continue;} chkmn(f[v],f[u]+1); if(!--d[v])q.push(v); } } } void get_ans(int m){ static int vis[4],s1,s2,s3,st[10],tp; for(int i=s1=s2=s3=0;i<4;++i)vis[i]=0; vis[st[tp=1]=a[0]]=1; for(int i=1;i<m;++i){ s1+=dis[a[i-1]][a[i]]; if(vis[a[i]]){ int lst=a[i]; while(1){ s2+=dis[st[tp]][lst];s3++; if(st[tp]==a[i])break; vis[st[tp]]=0; lst=st[tp--]; } continue; } vis[st[++tp]=a[i]]=1; } if(n<=s1)return; chkmx(ans, m); if(s2)chkmx(ans, m+1ll*(n-1-s1)/s2*s3); } void dfs(int x){ if(x>8)return; if(x>1)get_ans(x); for(int i=0;i<4;++i){ a[x]=i; dfs(x+1); } } int main(){ freopen("string.in","r",stdin); freopen("string.out","w",stdout); scanf("%lld%s",&n,s);l=strlen(s); cnt=1; for(int i=0,lst=1;i<l;++i){ int x=s[i]-'A',p=lst,np=++cnt; len[lst=np]=len[p]+1; while(p&&!ch[p][x])ch[p][x]=np,p=fa[p]; if(!p){fa[np]=1;continue;} int q=ch[p][x]; if(len[q]==len[p]+1)fa[np]=q; else{ int nq=++cnt; len[nq]=len[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[q])); fa[nq]=fa[q];fa[np]=fa[q]=nq; while(p&&ch[p][x]==q)ch[p][x]=nq,p=fa[p]; } } for(int i=0;i<4;++i)if(!ch[1][i]){return cout<<n<<endl,0;} memset(dis,0x3f,sizeof(dis)); memset(f,0x3f,sizeof(f)); for(int i=0;i<4;++i){ for(int j=1;j<=cnt;++j)d[j]=used[j]=0; pre_dfs(ch[1][i]); get_dis(i); } dfs(0); cout<<ans<<endl; return 0; }