• [CTSC 2012] Cheat


    [题目链接]

             https://www.lydsy.com/JudgeOnline/problem.php?id=2806

    [算法]

             首先建立广义后缀自动机

             注意到问题具有单调性 , 不妨对于每组询问二分答案mid

             如何检验?

             记fi表示前i个字符最多能选几个 , 有转移方程 :

              fi = max{ fi - 1 , fj + i - j } (i - maxlen[i] <= j <= i - mid)

              其中maxlen[i]表示第i个字符向前最多可匹配多少个字符

              i - maxlen[i]单调递增 , i - mid同样单调递增

             单调队列优化即可

             时间复杂度 : O(NlogN)

    [代码]

             

    #include<bits/stdc++.h>
    using namespace std;
    #define N 1100010
              
    int n , m , L;
    int dp[N] , maxlen[N] , q[N];
    char s[N];
    
    #define rint register int
    
    struct Suffix_Automaton
    {
        int sz , last;
        int father[N] , child[N][3] , depth[N];
        Suffix_Automaton()
        {
            sz = 1;
            last = 1;
        }
        inline int new_node(int dep)
        {
            depth[++sz] = dep;
            return sz;
        }
        inline void extend(int ch)
        {
            int np = new_node(depth[last] + 1);
            int p = last;
            while (child[p][ch] == 0)
            {
                child[p][ch] = np;
                p = father[p];
            }
            if (child[p][ch] == np) father[np] = 1;
            else
            {
                int q = child[p][ch];
                if (depth[q] == depth[p] + 1) father[np] = q;
                else
                {
                    int nq = new_node(depth[p] + 1);
                    father[nq] = father[q];
                    father[np] = father[q] = nq;
                    memcpy(child[nq] , child[q] , sizeof(child[q]));
                    while (child[p][ch] == q)
                    {
                        child[p][ch] = nq;
                        p = father[p];
                    }
                }
            }
            last = np;
          }
          inline void match()
          {
                  int now = 1 , mxlen = 0;
                  for (rint i = 1; i <= L; ++i)
                {
                        int nxt = s[i] - '0';
                              while (now != 1 && !child[now][nxt]) now = father[now] , mxlen = depth[now];
                    if (child[now][nxt]) 
                    {
                        ++mxlen;
                        now = child[now][nxt];
                    } else
                    {
                        mxlen = 0;
                        now = 1;
                    }
                    maxlen[i] = mxlen;
                }
                }
    } SAM;
    
    inline void chkmin(int &x , int y)
    {
            x = min(x , y);
    }
    inline void chkmax(int &x , int y)
    {
        x = max(x , y);
    }
    inline bool check(int mid)
    {
        int l = 1 , r = 0;
        for (rint i = 1; i < mid; ++i) dp[i] = 0;
        for (rint i = mid; i <= L; ++i)
        {
            while (l <= r && dp[q[r]] - q[r] <= dp[i - mid] - i + mid) --r;
            q[++r] = i - mid;
            while (l <= r && q[l] < i - maxlen[i]) ++l;
            dp[i] = dp[i - 1];
            if (l <= r) chkmax(dp[i] , dp[q[l]] - q[l] + i);    
        }    
        return dp[L] * 10 >= 9 * L;
    }
    
    int main()
    {
        
        scanf("%d%d" , &n , &m);
        int mxl = 0;
        for (rint i = 1; i <= m; ++i)
        {
            scanf("%s" , s + 1);
                    L = strlen(s + 1);
                    chkmax(mxl , L);
                    for (rint j = 1; j <= L; ++j) SAM.extend(s[j] - '0');
                    SAM.extend(2);
        }
        for (rint i = 1; i <= n; ++i)
        {
            scanf("%s" , s + 1);
            int l = 1 , r = strlen(s + 1) , ans = 0;
                    L = r;
                    chkmin(r , mxl);
            int now = 1 , mxlen = 0;
            SAM.match();
            while (l <= r)
            {
                int mid = (l + r) >> 1;
                if (check(mid))
                {
                    ans = mid;
                    l = mid + 1;
                } else r = mid - 1;
            }    
            printf("%d
    " , ans);
        }
        
        return 0;
    }

     

  • 相关阅读:
    Oracle中使用游标详解
    arc140 vp 记录
    CF1710D Recover theTree
    2022.8 做题记录
    21noip赛前20天 day10 简要题解
    2022.7.22 AGC028F&CF1463F&P7740
    arc141 vp 记录
    2022.7.25 AGC027F&AGC032F&AGC013F
    2022.7.21 AGC046D&P6790&AGC041F
    2022.7.20 AGC052D&P4338&AGC033E
  • 原文地址:https://www.cnblogs.com/evenbao/p/10623971.html
Copyright © 2020-2023  润新知