• [BZOJ4566][HAOI2016]找相同字符(SAM)


    4566: [Haoi2016]找相同字符

    Time Limit: 20 Sec  Memory Limit: 256 MB
    Submit: 950  Solved: 550
    [Submit][Status][Discuss]

    Description

    给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两
    个子串中有一个位置不同。

    Input

    两行,两个字符串s1,s2,长度分别为n1,n2。1 <=n1, n2<= 200000,字符串中只有小写字母

    Output

    输出一个整数表示答案

    Sample Input

    aabb
    bbaa

    Sample Output

    10

    HINT

    Source

    [Submit][Status][Discuss]

    后缀数组+单调栈可以做,但是后缀数组的超长模板加上单调栈的超多细节,想想就复杂。

    对于热爱DP或码力不够的选手,SAM则是最佳选择。

    给两个式子自己体会什么意思,很好理解。(tmp表示当前匹配上的长度)

    sum[i]=sum[fa[i]]+(l[i]-l[fa[i]])*right[i],ans+=sum[fa[p]]+(tmp-l[fa[p]])*right[p]

    radixsort然后拓扑DP即可,模板又打错了。。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=l; i<=r; i++)
     5 typedef long long ll;
     6 using namespace std;
     7 
     8 const int N=400100;
     9 char s1[N],s2[N];
    10 int n,m,p,lst=1,np,cnt=1,mx[N],right[N],fa[N],son[N][26],q[N],c[N];
    11 ll ans,sum[N];
    12 
    13 void ext(int c){
    14     p=lst; lst=np=++cnt; mx[np]=mx[p]+1; right[np]++;
    15     while (!son[p][c] && p) son[p][c]=np,p=fa[p];
    16     if (!p) fa[np]=1;
    17     else{
    18         int q=son[p][c];
    19         if (mx[q]==mx[p]+1) fa[np]=q;
    20         else{
    21             int nq=++cnt; mx[nq]=mx[p]+1;
    22             memcpy(son[nq],son[q],sizeof(son[q]));
    23             while (p && son[p][c]==q) son[p][c]=nq,p=fa[p];
    24             fa[nq]=fa[q]; fa[q]=fa[np]=nq;
    25         }
    26     }
    27 }
    28 
    29 void radix(){
    30     rep(i,0,n) c[i]=0;
    31     rep(i,1,cnt) c[mx[i]]++;
    32     rep(i,1,n) c[i]+=c[i-1];
    33     for (int i=cnt; i; i--) q[c[mx[i]]--]=i;
    34     for (int i=cnt; i; i--) right[fa[q[i]]]+=right[q[i]];
    35     rep(i,1,cnt) sum[q[i]]=sum[fa[q[i]]]+(mx[q[i]]-mx[fa[q[i]]])*right[q[i]];
    36 }
    37 
    38 void solve(){
    39     int tmp=0; p=1;
    40     rep(i,1,m){
    41         int c=s2[i]-'a';
    42         if (son[p][c]) p=son[p][c],tmp++;
    43         else{
    44             while (p && !son[p][c]) p=fa[p];
    45             if (!p) p=1,tmp=0; else tmp=mx[p]+1,p=son[p][c];
    46         }
    47         ans+=sum[fa[p]]+1ll*(tmp-mx[fa[p]])*right[p];
    48     }
    49 }
    50 
    51 int main(){
    52     freopen("bzoj4566.in","r",stdin);
    53     freopen("bzoj4566.out","w",stdout);
    54     scanf("%s",s1+1); n=strlen(s1+1);
    55     scanf("%s",s2+1); m=strlen(s2+1);
    56     rep(i,1,n) ext(s1[i]-'a');
    57     radix(); solve(); printf("%lld
    ",ans);
    58     return 0;
    59 }
  • 相关阅读:
    改变UIAlertController的标题、内容的字体和颜色
    mac 常用软件
    office web apps server 问题和解决办法
    如何在Excel中启用宏?
    System.Drawing.Image.Save(Savepath),保存为jpg格式,参数错误,文件0kb解决办法
    asp.net 1.1网站开发配置出现”Visual Studio .NET 无法创建或打开应用程序”解决方法
    map 遍历
    Java统计List集合中每个元素出现的次数
    sql 片段写法
    循环依赖
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8856770.html
Copyright © 2020-2023  润新知