• 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
    ",ans);
    116 }
  • 相关阅读:
    生成数据库结构设计说明书的存储过程
    C#检测上传图片是否安全函数
    设定下拉列表控件DropDownList,复选按钮CheckBox,RadioButton默认值总结测试
    C#批量重命名工具V2.0
    个人一些工作经验方式积累办法
    修身《孟子》尽心篇
    linux 命令 lspci lsusb
    重拾信心
    linux eclipse
    A lunch in Gordon Market with WWF
  • 原文地址:https://www.cnblogs.com/refun/p/10017635.html
Copyright © 2020-2023  润新知