2019年华南理工大学程序设计竞赛(春季赛) K Parco_Love_String(后缀自动机)找两个串的相同字串有多少
https://ac.nowcoder.com/acm/contest/625/K
题意:
给出Q 个询问 i , 求 s[0..i-1] 与 s[i...len-1] 有多少相同的字串
分析:
给出了查询 , 容易想到先预处理出答案好吧 , 字符串的问题也容易想到后缀自动机 ,但是我们该怎么使用呢?
下面提供我的思路;
我们建立出SAM后 , 跑一边拓扑排序 ,根据SAM跑出来的拓扑排序的序列特性 , 我们可以求出 在当前状态st 的最大串字符出现的个数
- for (int i = now; i >= ; --i) {///得到的是最大字符串的出现次数
- int x = rank[i];
- endpos[slink[x]] += endpos[x];
- }
可是这次我们需要求的是相同的串有多少 , 我们不可以暴力出SAM里面存有的串的个数 , 现在就来搞一个很奇妙的东西,
我们可以根据上面求出来的endpos , 去推出 有多少相同的字符串;
- for(int i= ; i<=now; i++)///得到全部串的出现次数
- {
- int x=rank[i]; ///到x这个状态时 , 有多少的后缀总共串
- sum[x] = sum[slink[x]] + endpos[x]*(maxlen[x] - maxlen[slink[x]]);
- //cout<<sum[x]<<endl;
- }
我们知道 对于 now1 , 与now2=slink[now1] , 如果now1状态出现了 , 那么now2 的状态也肯定会出现 , 因为silnk 是链接now1接下去的后缀 ,也就是说now2 是now1的后缀
所以我们求当前now 有多少串相同的时候 , 就要+上一个的后缀价值 sum[x] = sum[slink[x]】 + 当前的价值
当前的价值又是 怎么计算呢?
我们知道 maxlen[x] - maxlen[slink[x]] 是表示当前的状态x 里面有多少的串 , 那这个状态出现的次数与包含的串相乘 , 不就是当前我们需要求的价值了吗
上面可能说的比较乱 , 主要是我巨菜不知如何表达鸭
上面是用str1 串去构建的SAM , 然后用str2 在这个自动机里面跑 , 与求LCA 很相似
可以参考https://www.cnblogs.com/shuaihui520/p/10686862.html
- #include <bits/stdc++.h>
- #define LL long long
- #define P pair<int, int>
- #define lowbit(x) (x & -x)
- #define mem(a, b) memset(a, b, sizeof(a))
- #define rep(i, a, n) for (int i = a; i <= n; ++i)
- #define mid ((l + r) >> 1)
- #define lc rt<<1
- #define rc rt<<1|1
- #define ll long long
- using namespace std;
- const int maxn = ;
- struct SAM{
- int trans[maxn<<][], slink[maxn<<], maxlen[maxn<<];
- // 用来求endpos
- int indegree[maxn<<], endpos[maxn<<], rank[maxn<<], ans[maxn<<];
- // 计算所有子串的和(0-9表示)
- LL sum[maxn<<],D[maxn];
- int last, now, root;
- inline void newnode (int v) {
- maxlen[++now] = v;
- mem(trans[now],);
- }
- inline void extend(int c) {
- newnode(maxlen[last] + );
- int p = last, np = now;
- // 更新trans
- while (p && !trans[p][c]) {
- trans[p][c] = np;
- p = slink[p];
- }
- if (!p) slink[np] = root;
- else {
- int q = trans[p][c];
- if (maxlen[p] + != maxlen[q]) {
- // 将q点拆出nq,使得maxlen[p] + 1 == maxlen[q]
- newnode(maxlen[p] + );
- int nq = now;
- memcpy(trans[nq], trans[q], sizeof(trans[q]));
- slink[nq] = slink[q];
- slink[q] = slink[np] = nq;
- while (p && trans[p][c] == q) {
- trans[p][c] = nq;
- p = slink[p];
- }
- }else slink[np] = q;
- }
- last = np;
- // 初始状态为可接受状态
- endpos[np] = ;
- }
- inline void init()
- {
- root = last = now = ;
- slink[root]=;
- mem(trans[root],);
- mem(endpos,);
- mem(sum,);
- mem(indegree,);
- mem(rank,);
- }
- inline void getEndpos() {
- // topsort
- for (int i = ; i <= now; ++i) indegree[ maxlen[i] ]++; // 统计相同度数的节点的个数
- for (int i = ; i <= now; ++i) indegree[i] += indegree[i-]; // 统计度数小于等于 i 的节点的总数
- for (int i = ; i <= now; ++i) rank[ indegree[ maxlen[i] ]-- ] = i; // 为每个节点编号,节点度数越大编号越靠后
- // 从下往上按照slik更新
- for (int i = now; i >= ; --i) {///得到的是最大字符串的出现次数
- int x = rank[i];
- endpos[slink[x]] += endpos[x];
- }
- for(int i= ; i<=now; i++)///得到全部串的出现次数
- {
- int x=rank[i]; ///到x这个状态时 , 有多少的后缀总共串
- sum[x] = sum[slink[x]] + endpos[x]*(maxlen[x] - maxlen[slink[x]]);
- //cout<<sum[x]<<endl;
- }
- }
- ///用一个串去跑的自动机
- inline void work(string s,int W)
- {
- getEndpos();
- int len=s.size();
- int now=root;
- int t1=;
- ll ret=;
- for(int i= ; i<len ; i++)
- {
- int nowid=s[i]-'a';
- if(trans[now][nowid])///这个状态有了 , 去下一个状态找
- {
- t1++;
- now=trans[now][nowid];
- //ret+=sum[slink[now]] + endpos[now]*(t1-maxlen[slink[now]]);
- }
- else
- { while(now!= && trans[now][nowid]==) {now=slink[now];}///缩小范围找满足条件的
- if(now)
- {
- t1 = maxlen[now]+;
- now=trans[now][nowid];
- }
- else
- {
- t1=;now=root;
- }
- }
- ret+=sum[slink[now]] + endpos[now]*(t1-maxlen[slink[now]]);
- }
- D[W]=ret;
- //return ret;
- }
- }sam;
- int main()
- {
- string T;cin>>T;
- int len=T.size();
- for(int i= ; i<len ; i++)
- {
- string t2;
- sam.init();
- for(int j= ; j<i ; j++)
- {
- sam.extend(T[j]-'a');
- }
- for(int j=i ; j<len ; j++)
- {
- t2+=T[j];
- }
- sam.work(t2,i);
- }
- int E;scanf("%d",&E);
- while(E--)
- {
- int x;
- scanf("%d",&x);
- printf("%lld\n",sam.D[x]);
- }
- //- sam.all();
- }
2019年华南理工大学程序设计竞赛(春季赛) K Parco_Love_String(后缀自动机)找两个串的相同字串有多少的更多相关文章
- A NB群友 【记忆化搜索】(2019年华南理工大学程序设计竞赛(春季赛))
冲鸭!去刷题:https://ac.nowcoder.com/acm/contest/625/A 题目描述 CC是著名的算法竞赛选手,他不仅人长得帅,而且技术了得,自然而然就有了许多粉丝. 为了能帮助 ...
- 2019年华南理工大学程序设计竞赛(春季赛)-C-六学家的困惑
题目链接:https://ac.nowcoder.com/acm/contest/625/C 题意:给定两个字符串,每次只能从两个字符串的两端取字符,求依次取字符后所构成的数字最大为多少. 思路:思路 ...
- 2019年华南理工大学程序设计竞赛(春季赛)-H-Parco_Love_GCD
题目链接:https://ac.nowcoder.com/acm/contest/625/H 题意:给定n个数(<=1e9)的序列,其中n<=5e5,求该序列所有子序列的对应的gcd对1e ...
- C 六学家的困惑 【YY】 (2019年华南理工大学程序设计竞赛(春季赛))
冲鸭,去刷题:https://ac.nowcoder.com/acm/contest/625/C 小六喜欢两全其美的事情,今天就正好有一个这样的机会. 小六面前有两根管子,管子里面放满了数字为1到9的 ...
- 2019年华南理工大学程序设计竞赛(春季赛) B 修仙时在做什么?有没有空?可以来炼丹吗?(思维建图搜索)
https://ac.nowcoder.com/acm/contest/625/B 分析: 全部的状态只有1<<18 个 , 所以我们可以预处理 f[u][j] , 然后建立出全部的u可以 ...
- 2019年华南理工大学程序设计竞赛(春季赛)A NB群友
https://ac.nowcoder.com/acm/contest/625/A 题意:给出一个区间范围 , 求有多少个数的每一位的积是在这个区间里面的 分析:没错了 ,就是记忆化暴力搜索 ,不断的 ...
- 2018华南理工大学程序设计竞赛 H-对称与反对称
H-对称与反对称 题目描述 给出一个N*N的方阵A.构造方阵B,C: 使得A = B + C.其中 B为对称矩阵,C为反对称矩阵. 对于方阵S中的任意元素,若(S)ij = (S)ji,则称S为对称矩 ...
- “景驰科技杯”2018年华南理工大学程序设计竞赛 B. 一级棒!(并查集)
题目链接:https://www.nowcoder.com/acm/contest/94/B 题意:在一棵有 n 个节点的树上,有两种操作,一个是把 u 到 v 的路径走一遍,另一个是查询 u 到 f ...
- “景驰科技杯”2018年华南理工大学程序设计竞赛 A. 欧洲爆破(思维+期望+状压DP)
题目链接:https://www.nowcoder.com/acm/contest/94/A 题意:在一个二维平面上有 n 个炸弹,每个炸弹有一个坐标和爆炸半径,引爆它之后在其半径范围内的炸弹也会爆炸 ...
随机推荐
- [SoapUI] 通过SoapUI发送POST请求,请求的body是JSON格式的数据
通过SoapUI发送POST请求,请求的body是JSON格式的数据: data={"currentDate":"2015-06-19","reset ...
- 利用crosstool-ng自动化编译交叉编译环境(转)
原文地址:http://www.bootc.net/archives/2012/05/26/how-to-build-a-cross-compiler-for-your-raspberry-pi/ A ...
- mongodb 查询条件
这节来说说mongodb条件操作符,"$lt", "$lte", "$gt", "$gte", "$ne&qu ...
- 选项“6”对 /langversion 无效;必须是 ISO-1、ISO-2、3、4、5 或 Default
部署MVC的时候,因为服务器.NET版本是4.5.1,所以在vs将.NET版本降到4.5.1的时候发布报错. 原因:C#6降到C#5导致 解决办法:修改web.config配置 ,编译选项改为comp ...
- [GO]获取命令行参数
package main import ( "os" "fmt" ) func main() { list := os.Args n := len(list) ...
- javascript总结系列49:javaScript教程:原型链不可变
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8& ...
- 简单引入logback
pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w ...
- linux安装x264 ffmpeg
1. 安装yasm 2. 安装x264 3. 安装ffmpeg 安装网上很多例子,以下是我主要参考的两篇博客: http://www.cnblogs.com/lidabo/p/3987378.html ...
- Mac开发者常用的工具
http://www.oschina.net/news/53946/mac-dev-tools
- 【modelsim常见问题集锦】Can't launch the ModelSim-Altera software
一.Can't launch the ModelSim-Altera software Error: Can't launch the ModelSim-Altera software -- the ...