• [BZOJ4032][HEOI2015]最短不公共子串(Trie+DP)


    在虐各种最长公共子串、子序列的题虐的不耐烦了之后,你决定反其道而行之——被它们虐。

    操作一:对A,B分别建SAM,暴力BFS。

    操作二:对B建序列自动机或SAM,A在上面暴力匹配。

    操作三:对A,B建序列自动机,暴力匹配。

    操作四:对B建序列自动机,在自动机上DP。

    上面的我一句也看不懂,对不起我重说一遍。

    操作一:对B的所有后缀建Trie,A在上面暴力跑。$O(n^2)$

    操作二:枚举A的子串,在B上暴力匹配。$O(n^2)$

    操作三:在B的每个点上挂一个原本没有的叶子,将从根到这个叶子的路径形成的串扔到A上暴力跑匹配,若A有这个串则更新答案(因为是新叶子故B肯定没有这个串)。但这样似乎是$O(n^3*26)$的,注意枚举点的顺序,按建立顺序从后往前枚举,对于所有深度>=当前ans的直接跳过,这样就近似为$O(n^2*26)$了。似乎可以卡掉,但感觉并不会有出题人去卡。

    操作四:DP,f[i][j]表示A的前i个字符中选j个,在B的最小匹配末尾下标的最大值。每次只要从f[pre[i][c]][j-1]转移,其中pre[i][c]为A的第i个位置前的最接近i的字母c的位置。$O(n^2*26)$

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 using namespace std;
     6 
     7 const int N=2010,M=2000100,inf=1e9;
     8 int n,m,nd=1,ans,son[M][27],fa[M],dep[M],pre[N][27],nxt[N][27],f[N][N];
     9 char st[M],A[N],B[N],s[N];
    10 
    11 void ins(int d){
    12     int x=1;
    13     rep(i,d,m){
    14         int c=B[i]-'a'+1;
    15         if (!son[x][c]) son[x][c]=++nd,fa[nd]=x,st[nd]=B[i],dep[nd]=dep[x]+1;
    16         x=son[x][c];
    17     }
    18 }
    19 
    20 void walk(int d){
    21     int x=1;
    22     rep(i,d,n){
    23         int c=A[i]-'a'+1;
    24         if (!son[x][c]) { ans=min(ans,i-d+1); return; }
    25         x=son[x][c];
    26     }
    27 }
    28 
    29 void work(int d){
    30     int p=d;
    31     for (int i=1; i<=m && p<=n; i++)
    32         if (B[i]==A[p]) p++;
    33     if (p<=n) ans=min(ans,p-d+1);
    34 }
    35 
    36 void work2(int tot){
    37     int p=1;
    38     for (int i=1; i<=n && p<=tot; i++)
    39         if (A[i]==s[p]) p++;
    40     if (p>tot) ans=min(ans,tot);
    41 }
    42 
    43 void solve1(){
    44     ans=inf;
    45     rep(i,1,n) walk(i);
    46     printf("%d
    ",ans==inf ? -1 : ans);
    47 }
    48 
    49 void solve2(){
    50     ans=inf;
    51     rep(i,1,n) work(i);
    52     printf("%d
    ",ans==inf ? -1 : ans);
    53 }
    54 
    55 void solve3(){
    56     ans=inf;
    57     for (int i=nd; i; i--) if (dep[i]<ans){
    58         int tot=0;
    59         for (int k=i; k>1; k=fa[k]) s[++tot]=st[k];
    60         reverse(s+1,s+tot+1); tot++;
    61         rep(j,1,26) if (!son[i][j]) s[tot]=j+'a'-1,work2(tot);
    62     }
    63     printf("%d
    ",ans==inf ? -1 : ans);
    64 }
    65 
    66 void solve4(){
    67     ans=inf;
    68     rep(i,2,n){
    69         rep(j,1,26) pre[i][j]=pre[i-1][j];
    70         pre[i][A[i-1]-'a'+1]=i-1;
    71     }
    72     for (int i=n-1; ~i; i--){
    73         rep(j,1,26) nxt[i][j]=nxt[i+1][j];
    74         nxt[i][B[i+1]-'a'+1]=i+1;
    75     }
    76     rep(i,1,n){
    77         int t=nxt[0][A[i]-'a'+1];
    78         if (t) f[i][1]=max(f[i][1],t); else { puts("1"); return; }
    79     }
    80     rep(i,1,n) rep(j,2,i) rep(k,1,26) if (pre[i][k]){
    81         int t=nxt[f[pre[i][k]][j-1]][A[i]-'a'+1];
    82         if (!t) { ans=min(ans,j); break; }
    83         f[i][j]=max(f[i][j],t);
    84     }
    85     printf("%d
    ",ans==inf ? -1 : ans);
    86 }
    87 
    88 int main(){
    89     freopen("bzoj4032.in","r",stdin);
    90     freopen("bzoj4032.out","w",stdout);
    91     scanf("%s%s",A+1,B+1); n=strlen(A+1); m=strlen(B+1);
    92     rep(i,1,m) ins(i);
    93     solve1(); solve2(); solve3(); solve4();
    94     return 0;
    95 }

     

  • 相关阅读:
    python 面向对象专题(二):类的空间问题、类与对象之间的关系、类与类之间的关系
    python 面向对象专题(一):面向对象初识、面向对象结构、类、self、实例化对象
    数据可视化之PowerQuery篇(二十)如何计算在职员工数量?
    数据可视化之PowerQuery篇(十九)PowerBI数据分析实践第三弹 | 趋势分析法
    数据可视化之PowerQuery篇(十八)Power BI数据分析应用:结构百分比分析法
    数据可视化之PowerQuery篇(十七)Power BI数据分析应用:水平分析法
    ccoshf (Numerics) – C 中文开发手册
    HTML DOM removeAttribute() 方法
    curses.panel (Operating System) – Python 中文开发手册
    在Java中使用预定义的类名作为类或变量名称
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9885304.html
Copyright © 2020-2023  润新知