• Luogu P3181 [HAOI2016]找相同字符


    题意:两个字符串取出相同子串的方案数,方案不同当且仅当这两个子串中有一个位置不同。

    (SA) 后缀的前缀是子串,即求 (sum_{i<j} { m lcp}(suff_i,suff_j)),这个可以求出 (ht[]) 单调栈预处理。我们先把两个串拼起来算答案,然后再减去两个串分别计算的答案。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define R register int
    #define ll long long
    using namespace std;
    namespace Luitaryi {
    const int N=400010;
    int n,n1,n2; ll ans;
    int sa[N],rk[N],ht[N],c[N],x[N],y[N],l[N],r[N],stk[N],top;
    char s1[N>>1],s2[N>>1],s[N];
    inline void get_sa(char* s) {
      memset(c,0,sizeof c);
      memset(y,0,sizeof y);
      memset(x,0,sizeof x);
      R m=128;
      for(R i=1;i<=n;++i) ++c[x[i]=s[i]];
      for(R i=2;i<=m;++i) c[i]+=c[i-1];
      for(R i=n;i;--i) sa[c[x[i]]--]=i;
      for(R t=1,top=0;top<n;m=top,t<<=1) {
        top=0;
        for(R i=n-t+1;i<=n;++i) y[++top]=i;
        for(R i=1;i<=n;++i) if(sa[i]>t) y[++top]=sa[i]-t;
        memset(c,0,(m+1)<<2);
        for(R i=1;i<=n;++i) ++c[x[i]];
        for(R i=2;i<=m;++i) c[i]+=c[i-1];
        for(R i=n;i;--i) sa[c[x[y[i]]]--]=y[i];
        swap(x,y),x[sa[1]]=top=1;
        for(R i=2;i<=n;++i) 
          x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+t]==y[sa[i-1]+t])?top:++top;
      } for(R i=1;i<=n;++i) rk[sa[i]]=i;
    }
    inline void get_ht(char* s) {
      R k=0;
      for(R i=1,j;i<=n;++i) {
        if(k) --k; j=sa[rk[i]-1];
        while(s[j+k]==s[i+k]) ++k;
        ht[rk[i]]=k;
      }
    }
    inline ll solve() {
      register ll ret=0;
      stk[top=1]=1;
      for(R i=2;i<=n;++i) {
        while(top&&ht[stk[top]]>ht[i]) r[stk[top--]]=i;
        l[i]=stk[top]; stk[++top]=i;
      } while(top) r[stk[top--]]=n+1; 
      for(R i=1;i<=n;++i) 
        ret+=1ll*(r[i]-i)*(i-l[i])*ht[i];
      return ret;
    }
    inline void main() {
      scanf("%s",s1+1),n1=strlen(s1+1);
      scanf("%s",s2+1),n2=strlen(s2+1);
      memcpy(s+1,s1+1,n1),s[n1+1]='#';
      memcpy(s+n1+2,s2+1,n2);
      n=n1+n2+1,get_sa(s),get_ht(s),ans+=solve(); 
      n=n1,get_sa(s1),get_ht(s1),ans-=solve(); 
      n=n2,get_sa(s2),get_ht(s2),ans-=solve(); 
      printf("%lld
    ",ans);
    }
    } signed main() {Luitaryi::main(); return 0;}
    

    (SAM) 每个点的贡献是 ((l-{ m minlen}(now)+1) imes |{ m endpos}(now)|+sum_{pin ancestor(now)} ({ m maxlen}(p)-{ m minlen}(p)+1) imes |{ m endpos}(p)|,l为到now这个点匹配的长度)


    2020.01.09

  • 相关阅读:
    网络七层模型
    datagaridview添加序号
    sqlserver查询数据库所有字段和表的关系
    Code Project精彩系列转
    操作不同线程中的控件
    PetaPoco数据读写并发时出错
    浮点型float数据强制转换成int整型
    PetaPoco微型ORM的使用错误记录
    EF出现基础提供程序在 Open 上失败
    Python中random模块
  • 原文地址:https://www.cnblogs.com/Jackpei/p/12177341.html
Copyright © 2020-2023  润新知