BZOJ4180:字符串计数(SAM,二分,矩阵乘法)

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。

Solution

一篇写的很好的博客

Code

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<queue>
  5 #define N (200009)
  6 #define LL long long
  7 using namespace std;
  8 
  9 LL n,id;
 10 char s[N];
 11 queue<int>Q;
 12 int dis[N],vis[N];
 13 
 14 struct Matrix
 15 {
 16     LL m[5][5];
 17     Matrix(){memset(m,0,sizeof(m));}
 18 
 19     Matrix operator * (const Matrix &b) const
 20     {
 21         Matrix c;
 22         for (int i=0; i<4; ++i)
 23             for (int j=0; j<4; ++j)
 24                 c.m[i][j]=1e18;
 25         for (int k=0; k<4; ++k)
 26             for (int i=0; i<4; ++i)
 27                 for (int j=0; j<4; ++j)
 28                     c.m[i][j]=min(c.m[i][j],m[i][k]+b.m[k][j]);
 29         return c;
 30     }
 31 }A,G;
 32 
 33 Matrix Qpow(Matrix a,LL b)
 34 {
 35     Matrix ans;
 36     for (int i=0; i<4; ++i) ans.m[i][i]=1;
 37     while (b)
 38     {
 39         if (b&1) ans=ans*a;
 40         a=a*a; b>>=1;
 41     }
 42     return ans;
 43 }
 44 
 45 struct SAM
 46 {
 47     int son[N][4],fa[N],step[N];
 48     int p,q,np,nq,last,cnt;
 49     SAM(){last=cnt=1;}
 50 
 51     void Insert(int x)
 52     {
 53         p=last; np=last=++cnt; step[np]=step[p]+1;
 54         while (p && !son[p][x]) son[p][x]=np, p=fa[p];
 55         if (!p) fa[np]=1;
 56         else
 57         {
 58             q=son[p][x];
 59             if (step[q]==step[p]+1) fa[np]=q;
 60             else
 61             {
 62                 nq=++cnt; step[nq]=step[p]+1;
 63                 memcpy(son[nq],son[q],sizeof(son[q]));
 64                 fa[nq]=fa[q]; fa[q]=fa[np]=nq;
 65                 while (son[p][x]==q) son[p][x]=nq, p=fa[p];
 66             }
 67         }
 68     }
 69     void Build_Matrix()
 70     {
 71         for (int i=0; i<4; ++i)
 72             for (int j=0; j<4; ++j)
 73                 A.m[i][j]=1e18;
 74         for (int s=0; s<4; ++s)
 75         {
 76             while (!Q.empty()) Q.pop();
 77             memset(vis,false,sizeof(vis));
 78             vis[son[1][s]]=true;
 79             Q.push(son[1][s]); dis[son[1][s]]=1;
 80             while (!Q.empty())
 81             {
 82                 int x=Q.front(); Q.pop();
 83                 for (int i=0; i<4; ++i)
 84                     if (son[x][i] && !vis[son[x][i]])
 85                         vis[son[x][i]]=true,Q.push(son[x][i]),dis[son[x][i]]=dis[x]+1;
 86                     else A.m[s][i]=min(A.m[s][i],(LL)dis[x]);
 87             }
 88         }
 89     }
 90 }SAM;
 91 
 92 LL check(LL x)
 93 {
 94     LL Min=1e18;
 95     G=Qpow(A,x);
 96     for (int i=0; i<4; ++i)
 97         for (int j=0; j<4; ++j)
 98             Min=min(Min,G.m[i][j]);
 99     return Min>=n;
100 }
101 
102 int main()
103 {
104     scanf("%lld%s",&n,s);
105     for (int i=0,l=strlen(s); i<l; ++i)
106         SAM.Insert(s[i]-'A');
107     SAM.Build_Matrix();
108     LL l=0,r=1e18,ans;
109     while (l<=r)
110     {
111         LL mid=(l+r)>>1;
112         if (check(mid)) ans=mid,r=mid-1;
113         else l=mid+1;
114     }
115     printf("%lld\n",ans);
116 }
posted @ 2018-11-25 21:54  Refun  阅读(235)  评论(0编辑  收藏  举报