【AHOI2013】【BZOJ3238】差异

Description

Input

一行,一个字符串S

Output

一行。一个整数。表示所求值

Sample Input

cacao

Sample Output

54

HINT

2<=N<=500000,S由小写英文字母组成

后缀自己主动机的性质:

5.两个串的最长公共后缀,位于这两个串相应状态在Parent树上的近期公共祖先状态.

那么我们把原题里后缀的最长公共前缀反过来,把原串反过来建SAM就变成了最长公共后缀

然后题意就是求一个串全部前缀的最长公共后缀长度之和

我们能够在parent树上进行树形DP(按Po姐的说法事实上就是在后缀树上DP?)统计每一个点是多少点的LCA

对一个点统计子树两两right集合大小之积的和乘以深度

(别忘了是让你减掉这个东西)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 1000100
using namespace std;
char ch[MAXN];
int top;
long long ans;
struct edge
{
    int to;
    edge *next;
}e[MAXN],*prev[MAXN];
void insert(int u,int v)
{
    e[++top].to=v;e[top].next=prev[u];prev[u]=&e[top];
}
struct sam
{
    int last,cnt,p,q,np,nq;
    int len[MAXN],fa[MAXN],a[MAXN][26],size[MAXN];
    sam()
    {
        last=++cnt;
    }
    void insert(int c)
    {
        p=last;np=last=++cnt;len[np]=len[p]+1;size[np]=1;
        while (!a[p][c]&&p) a[p][c]=np,p=fa[p];
        if (!p) fa[np]=1;
        else
        {
            q=a[p][c];
            if (len[q]==len[p]+1)   fa[np]=q;
            else
            {
                nq=++cnt;len[nq]=len[p]+1;
                memcpy(a[nq],a[q],sizeof(a[q]));
                fa[nq]=fa[q];
                fa[q]=fa[np]=nq;
                while (a[p][c]==q)  a[p][c]=nq,p=fa[p];
            }
        }
    }
}sam;
void dfs(int x,int f)
{
    for (edge *i=prev[x];i;i=i->next)
    {
        dfs(i->to,x);
        sam.size[x]+=sam.size[i->to];
    }
    if (x==1)   return;
    sam.len[x]-=sam.len[f];
    ans-=(long long)sam.size[x]*(sam.size[x]-1)*sam.len[x];
}
int main()
{
    scanf("%s",ch);int Len=strlen(ch);
    for (int i=Len-1;i>=0;i--)  sam.insert(ch[i]-‘a‘);
    ans=(long long)(Len-1)*Len*(Len+1)>>1;
    for (int i=2;i<=sam.cnt;i++)    insert(sam.fa[i],i);
    dfs(1,0);
    cout<<ans<<endl;
}
时间: 2024-12-28 01:52:17

【AHOI2013】【BZOJ3238】差异的相关文章

【BZOJ3238】【AHOI2013】差异

sam好,好写好调好ac! 原题: 图片题面好评 2<=N<=500000 在syq大神的指点下终于理解一道后缀自动姬了quq (其实是因为这道题的dp主要是在后缀树(就是拓扑序)上搞树形dp-- 恩sam有个好玩的东西呢就是搞出后缀自动姬后根据max搞一个类似与后缀数组中countrank的东西 这个就是自动姬的拓扑序,同时也是parent树的不知道什么序,反正如果倒叙遍历这个序列的话x一定会比father[x]先访问到就对了 然后就可以直接用countrank搞树形dp辣 每个树点对答案的

【BZOJ3238】【Ahoi2013】差异 后缀自动机

转载请注明出处谢谢..http://blog.csdn.net/vmurder/article/details/42721101 首先 秦神QY Orz 题解: 这道题后缀数组过于鬼畜(wo'tai'ruo'bu'gan'xie) 所以写了简单好写易于理解不用分治不用RMQ的SAM大叔. 题解: 首先其实我们需要一个后缀树,然后两个后缀的lcp就是它们lca的len. 后缀树可以通过反序后缀自动机得到,这个很水. 然后len的性质就是后缀自动机的那个len(我写的'deep'). 后缀树上DP就

[bzoj3238]差异(后缀数组+单调栈)

显然我们可以先把len(Ti)+len(Tj)的值先算出来,再把LCP减去.所有len(Ti)+len(Tj)的值为n*(n-1)*(n+1)/2,这个随便在纸上画一画就可以算出来的. 接下来问题就是如何把LCP减去.我们先用后缀数组把height求出来,当有一段区间l~r,height[i]为height[l]~height[r]中的最小值,那么在l~r当中随便取两个后缀,他们的LCP则都是height[i],这个很好理解吧.那么l~r这个区间里有(l-i+1)*(r-i+1)对后缀,所以我们

【AHOI2013】差异

题面 题解 $ \because \sum_{1 \leq i < j \leq n} i + j = \frac{n(n-1)(n+1)}2 $ 所以只需求$\sum lcp(i,j)$即可. $ \because lcp(i,j)=\min_{rank[i] \leq k \leq rank[j]}\{height[k]\} $ 所以可以选用最小值分治算法: int min[maxn]; long long ans; void Div(int l, int r) { if(l == r) r

【AHOI2013】差异(2)

题面 https://www.luogu.org/problem/P4248 题解 这里,提供后缀数组的做法. #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> const int N=1000050; using namespace std; char s[N]; int n,m,rank[N],sa[N],tax[N],tp[N],height[N]; st

后缀自动机练习专题

后缀自动机练习专题 一些比较有用的东东: (1) \(\text{sam}\) 上一条从初始状态出发的路径对应一个子串 (2) \(\text{parent}\) 树上一个节点能表示的最长的串对应一个前缀/后缀 (3) \(len(u)\) 表示节点 \(u\) 能表示的最长串的长度 (4) \(fa(u)\) 表示节点 \(u\) 的后缀链接指向的节点,也就是其在 \(\text{parent}\) 树上的父亲 (5) 表示两个后缀的公共前缀的节点是两个后缀在 \(\text{parent}\

bzoj3238 [Ahoi2013]差异 后缀数组+单调栈

[bzoj3238][Ahoi2013]差异 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sample Output 54 题解: 任意两个字符串的lcp是什么,就是如 a,b  那么若a==b 那么为len(a) 否则设sa[a]<sa[b] 那么为min(height[sa[a]+1-------sa[b]]) 1 #include<cstring> 2 #include<iostrea

BZOJ3238: [Ahoi2013]差异

3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 437  Solved: 213[Submit][Status]Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacaoSample Output 54 HINT 2<=N<=500000,S由小写英文字母组成 题解: 刚看到题目,想着求出height然后搞出每个点作为最小值向右向左拓

【bzoj3238】[Ahoi2013]差异 后缀数组+单调栈

题目描述 输入 一行,一个字符串S 输出 一行,一个整数,表示所求值 样例输入 cacao 样例输出 54 题解 后缀数组+单调栈,几乎同 bzoj3879 的后半部分. 我明显是做题做反了... 这里还是说一下这道题的做法. 先用后缀数组求出height. 然后由于有LCP(a,c)=min(LCP(a,b),LCP(b,c))(rank[a]<rank[b]<rank[c]),所以我们只需要知道排名相邻的两个后缀的LCP,而这就是height数组的定义. 转化为子问题:给出n个数,求所有子