MZL's Circle Zhou

题意:给定两个长度不超过a,b(1 <= |a|,|b| <= 90000),x为a的连续子串,b为y的连续子串(x和y均可以是空串);问x+y形成的不同串的个数?

误区:开始一门心思想着求出总的可形成的字符串个数,再减去a,b中相同的子串重叠的部分;想通过连续插入a+b得到的SAM并不能获得信息;因为x,y是任意的子串,连续插入导致一定是a的后缀和b的前缀

正解:直接在计算有不同子串时,就不去计算重复的 <=>对于一个可能出现x后缀和y前缀相同而重复计算的情况,就全部加入x而y变为去掉前缀的部分;

即找到x最后一个字符ch,使得在x后能加的字符串不以ch开头,这样就避免了重复的情况;(思想很好啊!!!)

对SAM的理解:

SAM将字符串插入之后,step[np] - step[pre[np]]表示 状态np比父节点pre[np]多出的以相同的点为后缀的不同子串的个数;

对SAM进行拓扑之后:

<1>如果按照字符串先遍历有效节点,初始化每个状态出现的次数为1,就可从孩子节点得到父节点的出现的次数;再使用step得到不同子串的数目即可求解一类与出现次数有关的问题;如 hdu 4641 K-string

<2>如果初始化root为1,递推出每个节点出现的次数 cnt[ g[p][v] ] += cnt[p]将得到的是从初始状态到当前状态的所有子串(当然是不同的)数;

本题:需要对a字符串构成的SAM的每一个状态(节点)找出g[u][j] == 0(即上面讲的x不可能有j这条状态转移边),这时如果y以j开头的不同子串的数量已知,那就可以直接往结果中贡献出 cnt[u] * C[j]的值(cnt[u]表示a字符串以x状态为后缀不同子串的个数,C[j]表示y中以j开头子串的数目)

cnt集合根据上面的性质2可以直接递推得到,那C集合呢?

其实就是在找到一个cnt[u]之后,如果u有一条j的转移边j,那么C[j]的值就增加了cnt[u]?

还有一个问题:SAM只能求得以某个点为后缀的,怎么得到从每个点开始的呢?

那就将b逆序插入。。(好思想啊)这样后缀就变成了后缀里面的前缀

对于b的各种情况已经计算完了,但是由于可以有空子串,a的不同子串还需加上;

坑:这道题数据很大,怀疑是% unsigned long long判的结果,使用long long  直接WA了

注:如果C集合写在SAM里面,在调用SA时运算的SA的C集合。。不是SB的

 #include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef unsigned long long ll; const int maxn = ;
const int SIGMA_SIZE = ; struct SAM{
int sz, last, pos[maxn<<];
int g[maxn<<][SIGMA_SIZE], pre[maxn<<], step[maxn<<];
ll cnt[maxn<<]; void init(){
sz = ;last = ;
newNode();
} void newNode(int s){
pre[++sz] = ;
step[sz] = s;
memset(g[sz],,sizeof(g[sz]));
} int idx(char ch){ return ch - 'a'; } void Insert(char ch);
void topoSort();
void preSolve(ll* C);
ll solve(ll* C); }SA, SB; void SAM::Insert(char ch){
newNode(step[last] + );
int v = idx(ch), np = sz, p = last;
while(p && !g[p][v]){
g[p][v] = np;
p = pre[p];
} if(p){
int q = g[p][v];
if(step[q] == step[p] + )
pre[np] = q;
else{
newNode(step[p] + );
int nq = sz;
for(int i = ;i < SIGMA_SIZE;i++)
g[nq][i] = g[q][i]; pre[nq] = pre[q];
pre[q] = pre[np] = nq; while(p && g[p][v] == q)
g[p][v] = nq, p = pre[p];
}
}
else pre[np] = ;
last = np;
} void SAM::topoSort(){
for(int i = ; i <= sz; i++) cnt[i] = ;
for(int i = ; i <= sz; i++) cnt[step[i]]++;
for(int i = ; i <= sz; i++) cnt[i] += cnt[i-];
for(int i = ; i <= sz; i++) pos[cnt[step[i]]--] = i;
} void SAM::preSolve(ll* C){
topoSort();
for(int i = ;i <= sz; i++) cnt[i] = ;
cnt[] = ; for(int i = ;i <= sz; i++){  //从root递推到每个节点出现的次数
int u = pos[i];
for(int j = ; j < SIGMA_SIZE; j++){
int v = g[u][j];
if(v == ) continue;
C[j] += cnt[u];
cnt[v] += cnt[u];
}
}
} ll SAM::solve(ll *C){
topoSort();
for(int i = ; i <= sz; i++) cnt[i] = ;
cnt[] = ; ll ret = ;
for(int i = ; i <= sz; i++){
int u = pos[i];
for(int j = ; j < SIGMA_SIZE; j++){
int v = g[u][j];
if(v == ) ret += cnt[u] * C[j];
else cnt[v] += cnt[u];
}
ret += cnt[u];    // x + ""
}
return ret;
} char str[maxn];
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%s", str);
int n = strlen(str);
SA.init();
for(int i = ;i < n; i++)
SA.Insert(str[i]); scanf("%s", str);
n = strlen(str);
SB.init();
for(int i = n - ; i >= ; i--)    // **
SB.Insert(str[i]); ll C[SIGMA_SIZE];
memset(C,,sizeof(C));
SB.preSolve(C); printf("%llu\n",SA.solve(C));
}
}

hdu 5343 MZL's Circle Zhou SAM的更多相关文章

  1. HDU 5343 MZL's Circle Zhou

    MZL's Circle Zhou Time Limit: 1000ms Memory Limit: 131072KB This problem will be judged on HDU. Orig ...

  2. HDU 5343 MZL's Circle Zhou 后缀自动机+DP

    MZL's Circle Zhou Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  3. HDU5343 MZL's Circle Zhou(SAM+记忆化搜索)

    Problem Description MZL's Circle Zhou is good at solving some counting problems. One day, he comes u ...

  4. HDU5343:MZL's Circle Zhou(SAM,记忆化搜索DP)

    Description Input Output Sample Input Sample Output Solution 题意:给你两个串,分别从两个里面各选出一个子串拼到一起,问能构成多少个本质不同 ...

  5. [HDU5343]MZL's Circle Zhou

    题目大意: 给你两个字符串a和b,从中分别取出子串x和y,求不同的x+y的个数. 思路: 对于每一个字符串,构建SAM. 为了保证相同的x+y不会被重复统计,我们可以想办法只统计相同的x+y中x最长的 ...

  6. HDU 5351 MZL's Border (规律,大数)

    [HDU 5351 MZL's Border]题意 定义字符串$f_1=b,f_2=a,f_i=f_{i-1}f_{i-2}$. 对$f_n$的长度为$m$的前缀$s$, 求最大的$k$满足$s[1] ...

  7. Hdu 5352 MZL's City (多重匹配)

    题目链接: Hdu 5352 MZL's City 题目描述: 有n各节点,m个操作.刚开始的时候节点都是相互独立的,一共有三种操作: 1:把所有和x在一个连通块内的未重建过的点全部重建. 2:建立一 ...

  8. Hdu 5348 MZL's endless loop (dfs)

    题目链接: Hdu 5348 MZL's endless loop 题目描述: 给出一个无向图(有环,有重边),包含n个顶点,m条边,问能否给m条边指定方向,使每个顶点都满足abs(出度-入度)< ...

  9. hdu 5349 MZL's simple problem

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5349 MZL's simple problem Description A simple proble ...

随机推荐

  1. this的分析

    this是js中的一个关键字,当函数运行时,会自动生成的一个对象,只能在函数内部使用.随着函使用场合不同,this值会变化,但是始终指向调用函数的那个对象. 1.纯粹的函数调用 function bo ...

  2. 如何用拉姆达表达式(Lambda Expressions) 书写左链接查询

    在C#中,如果要实现两个列表的左链接查询,我们的一般用法就是用的linq表达式就是 List<Pet> pets = }, }, } }; List<Pet2> pets2 = ...

  3. ubuntu14_pip 安装

    1:install pip python-dev    sudo apt-get install python-dev    sudo apt-get install libevent-dev     ...

  4. 一个把List<String>转化为以","隔开的字符串的方法

    import java.util.ArrayList; import java.util.List; /** * 集合操作 * @author intrl * @date 2010-12-15 * @ ...

  5. [改善Java代码] 避免instanceof非预期结果

    建议18: 避免instanceof非预期结果 instanceof是一个简单的二元操作符,它是用来判断一个对象是否是一个类实例的,其操作类似于>=.==,非常简单,我们来看段程序,代码如下: ...

  6. Java从Jar文件中动态加载类

    动态加载jar包,在实际开发中经常会需要用到,尤其涉及平台和业务的关系的时候,业务逻辑部分可以独立出去交给业务方管理,业务方只需要提供jar包,就能在平台上运行. 下面通过一个实例来直观演示: 第一: ...

  7. hdu 4340 树状DP

    思路:我们定义两个数组,ant[Maxn][2],bob[Maxn][2].ant[i][0]表示还未确定哪个城市被全费用占领,ant[i][1]表示确定了哪个城市被全费用占领.那么ant[i][0] ...

  8. Git CMD - status: Show the working tree status

    命令参数 git status [<options>…​] [--] [<pathspec>…​] 命令格式 --short, -s 短格式输出. -- long 长格式输出, ...

  9. 备忘====[HttpPost]和[AcceptVerbs(HttpVerbs.Post)]区别

    1.共同点:[HttpPost]和[AcceptVerbs(HttpVerbs.Post)]都是只接受POST请求过来的数据. 2.不同点:在MVC中如果想一个action既可以回应POST请求也可以 ...

  10. 32位和64位Ghost版Win8.1系统大全下载最新版

    Ghost版Win8.1系统企业版,下载完成后一定要使用校验工具验证GHO文件MD5值,如果不符请不要安装,不然安装失败后果自负.GHO文件路径一定不要带中文,否则无法安装.安装完成第一次进入桌面会黑 ...