Description
SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999。
他给出了一个字符串T,字符串T中有且仅有4种字符 ‘A’, ‘B’, ‘C’, ‘D’。现在他要求蒟蒻yts1999构造一个新的字符串S,构造的方法是:进行多次操作,每一次操作选择T的一个子串,将其加入S的末尾。
对于一个可构造出的字符串S,可能有多种构造方案,Oxer定义构造字符串S所需的操作次数为所有构造方案中操作次数的最小值。
Oxer想知道对于给定的正整数N和字符串T,他所能构造出的所有长度为N的字符串S中,构造所需的操作次数最大的字符串的操作次数。
蒟蒻yts1999当然不会做了,于是向你求助。
Input
第一行包含一个整数N,表示要构造的字符串长度。
第二行包含一个字符串T,T的意义如题所述。
Output
输出文件包含一行,一个整数,为你所求出的最大的操作次数。
Sample Input
5
ABCCAD
Sample Output
5
HINT
【样例说明】
例如字符串”AAAAA”,该字符串所需操作次数为5,不存在能用T的子串构造出的,且所需操作次数比5大的字符串。
【数据规模和约定】
对于100%的数据,1 ≤ N ≤ 10^18,1 ≤ |T| ≤ 10^5。
Source
By yts1999
建出SAM,然后构造一个矩阵
Lcomyn当时抓了这题当胡策题,今天补全一下
他的ppt题解有误请不要找我(逃
大家自己感受一下ppt哪里写的有问题就行了
然而YJQ有不需要二分,只用倍增Floyd的做法哦
复杂度少个log,感觉神神哒
另外我觉得此题是一道SAM好题.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define MAXN 200010
#define LL long long
#define MAXLL 1ll<<62
using namespace std;
LL n;
char ch[MAXN];
struct Matrix
{
LL a[4][4];
inline friend Matrix operator * (const Matrix A,const Matrix B)
{
Matrix ret;
for (int i=0;i<4;i++) for (int j=0;j<4;j++)
{
ret.a[i][j]=MAXLL;
for (int k=0;k<4;k++) ret.a[i][j]=min(ret.a[i][j],A.a[i][k]+B.a[k][j]);
}
return ret;
}
inline friend Matrix operator ^ (const Matrix A,LL k)
{
Matrix ret,tmp=A;for (int i=0;i<4;i++) for (int j=0;j<4;j++) ret.a[i][j]=(i==j)?1:0;
for (;k;k>>=1,tmp=tmp*tmp) if (k&1) ret=ret*tmp;
return ret;
}
}init;
struct sam
{
int p,q,np,nq,last,cnt;
LL minn[MAXN][4];
int a[MAXN][4],fa[MAXN],len[MAXN];
bool vis[MAXN];
sam() { last=++cnt; }
inline void insert(int c)
{
p=last;np=last=++cnt;len[np]=len[p]+1;
while (!a[p][c]&&p) a[p][c]=np,p=fa[p];
if (!p) fa[np]=1;
else
{
q=a[p][c];
if (len[q]==len[p]+1) fa[np]=q;
else
{
nq=++cnt;len[nq]=len[p]+1;memcpy(a[nq],a[q],sizeof(a[q]));
fa[nq]=fa[q];fa[q]=fa[np]=nq;
while (a[p][c]==q) a[p][c]=nq,p=fa[p];
}
}
}
void dfs(int x)
{
vis[x]=1;
for (int i=0;i<4;i++)
{
if (a[x][i]&&!vis[a[x][i]]) dfs(a[x][i]);
minn[x][i]=a[x][i]?MAXLL:1ll;
}
for (int i=0;i<4;i++)
if (a[x][i])
for (int j=0;j<4;j++) minn[x][j]=min(minn[x][j],minn[a[x][i]][j]+1);
}
}sam;
inline bool check(LL x)
{
Matrix mat=init^x;
for (int i=0;i<4;i++) for (int j=0;j<4;j++) if (mat.a[i][j]+1<=n) return 1;
return 0;
}
int main()
{
cin>>n;scanf("%s",ch+1);int len=strlen(ch+1);LL ans=0,l,r,mid;
for (int i=1;i<=len;i++) sam.insert(ch[i]-'A');
sam.dfs(1);
for (int i=0;i<4;i++) for (int j=0;j<4;j++) init.a[i][j]=sam.minn[sam.a[1][i]][j];
for (l=0,r=n+1,mid=(l+r)>>1;l<=r;mid=(l+r)>>1) if (check(mid)) l=mid+1; else r=(ans=mid)-1;
cout<<ans;
}