当前位置: 首页 > news >正文

Luogu P3181 [HAOI2016]找相同字符 广义$SAM$

题目链接 \(Click\) \(Here\)

设一个串\(s\)\(A\)中出现\(cnt[s][1]\)次,在\(B\)中出现\(cnt[s][2]\)次,我们要求的就是:

\[\sum cnt[s][1]*cnt[s][2]\]

\(SAM\)这种把多个串用一个点表示的东西里,答案就变成了这个

\[\sum cnt[s][1] * cnt[s][2] * (len[fa[s]]-len[s])\]

其中的\(cnt\)求法,听说好像可以两个串隔开求?但是我不太会。学了一下用广义\(SAM\)的写法,似乎是第一个串建完之后把\(las\)指针指回根节点,再建第二个就好。因为网上对于这种写法各种声音都有,所以我打算这周末认真学习\(SA\)\(SAM\)后再详细进行解释说明或者算法更正。

\(p.s\)这种写法下似乎不能以\(len\)桶排序求\(cnt\),因为\(len\)会有相等情况。所以我们要用\(Parent\) \(Tree\)\(DP\)来写。

最后提醒:别忘\(long\) \(long\)

#include <bits/stdc++.h>
using namespace std;

const int N = 800010;
typedef long long ll;

ll tot[2][N];
int node = 1, las = 1;
int fa[N], len[N], ch[N][26];



void extend (int c, int id) {
    int p = las, q = ++node;
    len[q] = len[p] + 1, tot[id][q] = 1, las = q;
    while (p != 0 && ch[p][c] == 0) {
        ch[p][c] = q;
        p = fa[p];
    }
    if (p == 0) {
        fa[q] = 1;
    } else {
        int x = ch[p][c];
        if (len[x] == len[p] + 1) {
            fa[q] = x;
        } else {
            int y = ++node;
            len[y] = len[p] + 1;
            fa[y] = fa[x];
            fa[x] = fa[q] = y;
            memcpy (ch[y], ch[x], sizeof (ch[x]));
            while (p != 0 && ch[p][c] == x) {
                ch[p][c] = y;
                p = fa[p];
            }
        }
    }
}
    
int cnt, head[N];

struct edge {
    int nxt, to;
}e[N];

void add_edge (int from, int to) {
    e[++cnt].nxt = head[from];
    e[cnt].to = to;
    head[from] = cnt;
}

void dfs (int u) {
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        dfs (v);
        tot[0][u] += tot[0][v];
        tot[1][u] += tot[1][v];
    }
}

ll get_ans () {
    ll ans = 0;
    for (int i = 1; i <= node; ++i) add_edge (fa[i], i); dfs (1);
    for (int i = 1; i <= node; ++i) ans += 1LL * (len[i] - len[fa[i]]) * tot[0][i] * tot[1][i];
    return ans;
} 

int n1, n2;
char s1[N], s2[N];

int main () {
    scanf ("%s %s", s1, s2);
    n1 = strlen (s1), n2 = strlen (s2);
    for (int i = 0; i < n1; ++i) extend (s1[i] - 'a', 0);
    las = 1;
    for (int i = 0; i < n2; ++i) extend (s2[i] - 'a', 1);
    cout << get_ans () << endl;
} 

转载于:https://www.cnblogs.com/maomao9173/p/10459223.html

相关文章:

  • 主流视音频平台参数
  • python中的with语句
  • LAV Filter 源代码分析 4: LAV Video (2)
  • CSS:z-index
  • RDS-Mysql 物理备份恢复到本地数据库上
  • 客户端网络库实现真的很简单吗?
  • HTPC家庭娱乐和XBOX未来发展畅想另:创业工作机会
  • Socket IO与NIO(四)
  • 【算法导论】学习笔记——第6章 堆排序
  • 转:网络协议概览
  • 5分钟了解 Python 中的super函数是如何实现继承的
  • LINQ To SQL在N层应用程序中的CUD操作、批量删除、批量更新
  • 问题:什么情况UDP的非阻塞写会失败?
  • 一次服务器CPU占用率高的定位分析
  • [HNOI2015]实验比较
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • AHK 中 = 和 == 等比较运算符的用法
  • chrome扩展demo1-小时钟
  • Go 语言编译器的 //go: 详解
  • Logstash 参考指南(目录)
  • python学习笔记 - ThreadLocal
  • Vue学习第二天
  • 简单实现一个textarea自适应高度
  • 名企6年Java程序员的工作总结,写给在迷茫中的你!
  • 如何利用MongoDB打造TOP榜小程序
  • 一起参Ember.js讨论、问答社区。
  • scrapy中间件源码分析及常用中间件大全
  • Spring Batch JSON 支持
  • #快捷键# 大学四年我常用的软件快捷键大全,教你成为电脑高手!!
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • (23)Linux的软硬连接
  • (vue)el-checkbox 实现展示区分 label 和 value(展示值与选中获取值需不同)
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (四) Graphivz 颜色选择
  • (四)【Jmeter】 JMeter的界面布局与组件概述
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • (淘宝无限适配)手机端rem布局详解(转载非原创)
  • (转)Android学习笔记 --- android任务栈和启动模式
  • (转)Linux整合apache和tomcat构建Web服务器
  • (转)关于pipe()的详细解析
  • (转)用.Net的File控件上传文件的解决方案
  • ***微信公众号支付+微信H5支付+微信扫码支付+小程序支付+APP微信支付解决方案总结...
  • **Java有哪些悲观锁的实现_乐观锁、悲观锁、Redis分布式锁和Zookeeper分布式锁的实现以及流程原理...
  • .gitignore文件---让git自动忽略指定文件
  • .net core 控制台应用程序读取配置文件app.config
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .net6Api后台+uniapp导出Excel
  • .NET使用HttpClient以multipart/form-data形式post上传文件及其相关参数
  • .net专家(张羿专栏)
  • /var/spool/postfix/maildrop 下有大量文件
  • @Responsebody与@RequestBody
  • @RunWith注解作用
  • [ vulhub漏洞复现篇 ] Celery <4.0 Redis未授权访问+Pickle反序列化利用