zoukankan      html  css  js  c++  java
  • CF700E Cool Slogans [后缀自动机,线段树合并,树形dp]

    题意:

    我们定义 (forall i ,s_i) 是给定串 (S) 的子串,且 (s_{i-1})(s_{i}) 要出现至少两次。求最大的 (k),使得 (forall i,s_i in S)

    sol:

    我们考虑到,对于一个点 (i)(fa_i)(i) 的子串,并且是后缀,我们定义 (g_i) 是上次匹配到的点,(f_i) 是匹配到这个点的最长长度,那么一定是能匹配就匹配,这样显然是最优的,不能就复制父节点信息接着往下玩。

    我们考虑到 (1) ~ (i) 的一条链上后缀都相同但是长度不同。

    然后我们要考虑如果 (g_u) 的子树包含 (v),那么 (g_u) 对应的字符串在 (v) 对应的字符串 出现了一次,易证。

    所以我们只需要线段树合并出来每个点 (i) 的子树信息就可以了。就是说哪个出现过哪个没出现过。

    然后的话我们就考虑一下另一次出现怎么求呢。显然你出现的位置是 (pos_v) 那么我们要把 (pos_v) 这个点去掉。并且我们要在 ([pos_v - len_v + len_{g_u} , pos_v - 1]) 这段区间内找到点。

    为什么,我们考虑一下,(len_v)(v) 所对应的字符串的长度,那么 (len_{g_u}) 同理,因为你的上个转移点是 (g_u) 所以显然是 (g_u) 但是长度至少为 (len_{g_u}) 所以最后一个点必须在 (pos_v - len_v + len_{g_u}) 后面。

    代码挺好写的.jpg

    code:

    // clang-format off
    // powered by c++11
    // by Isaunoya
    #include<bits/stdc++.h>
    #define rep(i,x,y) for(register int i=(x);i<=(y);++i)
    #define Rep(i,x,y) for(register int i=(x);i>=(y);--i)
    using namespace std;using db=double;using ll=long long;
    using uint=unsigned int;using ull=unsigned long long;
    using pii=pair<int,int>;
    #define Tp template
    #define fir first
    #define sec second
    Tp<class T>void cmax(T&x,const T&y){if(x<y)x=y;}Tp<class T>void cmin(T&x,const T&y){if(x>y)x=y;}
    #define all(v) v.begin(),v.end()
    #define sz(v) ((int)v.size())
    #define pb emplace_back
    Tp<class T>void sort(vector<T>&v){sort(all(v));}Tp<class T>void reverse(vector<T>&v){reverse(all(v));}
    Tp<class T>void unique(vector<T>&v){sort(all(v)),v.erase(unique(all(v)),v.end());}inline void reverse(string&s){reverse(s.begin(),s.end());}
    const int SZ=1<<23|233;
    struct FILEIN{char qwq[SZ],*S=qwq,*T=qwq,ch;
    #ifdef __WIN64
    #define GETC getchar
    #else
    inline char GETC(){return(S==T)&&(T=(S=qwq)+fread(qwq,1,SZ,stdin),S==T)?EOF:*S++;}
    #endif
    inline FILEIN&operator>>(char&c){while(isspace(c=GETC()));return*this;}inline FILEIN&operator>>(string&s){s.clear();while(isspace(ch=GETC()));if(!~ch)return*this;s=ch;while(!isspace(ch=GETC())&&~ch)s+=ch;return*this;}
    inline FILEIN&operator>>(char*str){char*cur=str;while(*cur)*cur++=0;cur=str;while(isspace(ch=GETC()));if(!~ch)return*this;*cur=ch;while(!isspace(ch=GETC())&&~ch)*++cur=ch;*++cur=0;return*this;}
    Tp<class T>inline void read(T&x){bool f=0;while((ch=GETC())<48&&~ch)f^=(ch==45);x=~ch?(ch^48):0;while((ch=GETC())>47)x=x*10+(ch^48);x=f?-x:x;}
    inline FILEIN&operator>>(int&x){return read(x),*this;}inline FILEIN&operator>>(ll&x){return read(x),*this;}inline FILEIN&operator>>(uint&x){return read(x),*this;}inline FILEIN&operator>>(ull&x){return read(x),*this;}
    inline FILEIN&operator>>(double&x){read(x);bool f=x<0;x=f?-x:x;if(ch^'.')return*this;double d=0.1;while((ch=GETC())>47)x+=d*(ch^48),d*=.1;return x=f?-x:x,*this;}
    }in;
    struct FILEOUT{const static int LIMIT=1<<22;char quq[SZ],ST[233];int sz,O,pw[233];
    FILEOUT(){set(7);rep(i,pw[0]=1,9)pw[i]=pw[i-1]*10;}~FILEOUT(){flush();}
    inline void flush(){fwrite(quq,1,O,stdout),fflush(stdout),O=0;}
    inline FILEOUT&operator<<(char c){return quq[O++]=c,*this;}inline FILEOUT&operator<<(string str){if(O>LIMIT)flush();for(char c:str)quq[O++]=c;return*this;}
    inline FILEOUT&operator<<(char*str){if(O>LIMIT)flush();char*cur=str;while(*cur)quq[O++]=(*cur++);return*this;}
    Tp<class T>void write(T x){if(O>LIMIT)flush();if(x<0){quq[O++]=45;x=-x;}do{ST[++sz]=x%10^48;x/=10;}while(x);while(sz)quq[O++]=ST[sz--];}
    inline FILEOUT&operator<<(int x){return write(x),*this;}inline FILEOUT&operator<<(ll x){return write(x),*this;}inline FILEOUT&operator<<(uint x){return write(x),*this;}inline FILEOUT&operator<<(ull x){return write(x),*this;}
    int len,lft,rig;void set(int l){len=l;}inline FILEOUT&operator<<(double x){bool f=x<0;x=f?-x:x,lft=x,rig=1.*(x-lft)*pw[len];return write(f?-lft:lft),quq[O++]='.',write(rig),*this;}
    }out;
    #define int long long
    struct Math{
    vector<int>fac,inv;int mod;
    void set(int n,int Mod){fac.resize(n+1),inv.resize(n+1),mod=Mod;rep(i,fac[0]=1,n)fac[i]=fac[i-1]*i%mod;inv[n]=qpow(fac[n],mod-2);Rep(i,n-1,0)inv[i]=inv[i+1]*(i+1)%mod;}
    int qpow(int x,int y){int ans=1;for(;y;y>>=1,x=x*x%mod)if(y&1)ans=ans*x%mod;return ans;}int C(int n,int m){if(n<0||m<0||n<m)return 0;return fac[n]*inv[m]%mod*inv[n-m]%mod;}
    int gcd(int x,int y){return!y?x:gcd(y,x%y);}int lcm(int x,int y){return x*y/gcd(x,y);}
    }math;
    // clang-format on
    int n;
    const int maxn = 4e5 + 54;
    char s[maxn];
    
    int rt[maxn];
    struct SegMentTree {
      const static int maxnode = maxn << 5;
      int ls[maxnode], rs[maxnode], cnt;
    
      SegMentTree() { cnt = 0; }
    
      void upd(int& p, int l, int r, int x) {
        if (!p) p = ++cnt;
        if (l == r) return;
        int mid = l + r >> 1;
        if (x <= mid)
          upd(ls[p], l, mid, x);
        else
          upd(rs[p], mid + 1, r, x);
      }
    
      int merge(int x, int y) {
        if (!x || !y) return x | y;
        int qwq = ++cnt;
        ls[qwq] = merge(ls[x], ls[y]);
        rs[qwq] = merge(rs[x], rs[y]);
        return qwq;
      }
    
      int qry(int p, int a, int b, int l, int r) {
        if (!p) return 0;
        if (a <= l && r <= b) return 1;
        int mid = l + r >> 1, ans = 0;
        if (a <= mid) ans += qry(ls[p], a, b, l, mid);
        if (b > mid) ans += qry(rs[p], a, b, mid + 1, r);
        return ans;
      }
    } smt;
    
    int ans = 1;
    struct SAM {
      int ch[maxn][26], fa[maxn], len[maxn], pos[maxn], las, cnt;
      SAM() { las = cnt = 1; }
    
      void add(int c, int id) {
        int p = las, np = las = ++cnt;
        pos[np] = id, len[np] = len[p] + 1, smt.upd(rt[np], 1, n, id);
        for (; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
        if (!p) {
          fa[np] = 1;
        } else {
          int q = ch[p][c];
          if (len[q] == len[p] + 1) {
            fa[np] = q;
          } else {
            int nq = ++cnt;
            memcpy(ch[nq], ch[q], sizeof(ch[q]));
            pos[nq] = pos[q], fa[nq] = fa[q], fa[q] = fa[np] = nq, len[nq] = len[p] + 1;
            for (; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
          }
        }
      }
    
      vector<int> g[maxn];
      void dfs(int u) {
        for (int v : g[u]) {
          dfs(v);
          rt[u] = smt.merge(rt[u], rt[v]);
        }
      }
    
      void build(char* s) {
        char* cur = s;
        int id = 0;
        while (*cur) {
          int c = (*cur++) - 'a';
          add(c, ++id);
        }
        rep(i, 2, cnt) g[fa[i]].pb(i);
      }
    
      int f[maxn], G[maxn];
      void dfs2(int u) {
        for (int v : g[u]) {
          if (fa[v] == 1) {
            f[v] = 1, G[v] = v;
          } else {
            if (smt.qry(rt[G[u]], pos[v] - (len[v] - len[G[u]]), pos[v] - 1, 1, n))
              f[v] = f[u] + 1, G[v] = v;
            else
              f[v] = f[u], G[v] = G[u];
          }
          dfs2(v);
        }
        cmax(ans, f[u]);
      }
    } sam;
    
    signed main() {
      // code begin.
      in >> n >> s, sam.build(s), sam.dfs(1), sam.dfs2(1);
      out << ans << '
    ';
      return 0;
      // code end.
    }
    
  • 相关阅读:
    675 对象的引用-浅拷贝-深拷贝
    674 vue3侦听器watch
    673 vue计算属性:缓存,setter和getter
    明明有了promise,为啥还需要async await?
    Js常用数组方法汇总
    一些非常有用的Js单行代码
    Js获取验证码倒计时
    前端截取字符串:JS截取字符串之substring、substr和slice详解
    javascript全局变量与局部变量
    JS实现快速排序算法
  • 原文地址:https://www.cnblogs.com/Isaunoya/p/12549395.html
Copyright © 2011-2022 走看看