补博客!

首先我们观察题目中给的那个求\(ans\)的方法,其实前两项没什么用处,直接\(for\)一遍就求得了

for (int i=1;i<=n;i++) ans=ans+i*(n-1);

那么我们考虑剩下的部分应该怎么求解!

首先这里有一个性质。对于任意两个后缀\(i,j\),他们的\(lcp\)长度是他们对应的\(rank\)之间的\(height\)的\(min\) (左开右闭)

或者这样说

\(lcp(i,j) = min(height[rank[i]+1],height[rank[i]+2].....,height[rank[j]]) 其中rank[i]<rank[j]\)

那么对于这个题,我们就可以直接维护出每个\(height\)作为最小值的区间,然后用他的区间个乘上贡献即可(但是具体这里求的时候需要仔细想想,因为那个左开右闭的区间,假设右边能选的端点是\(r[i]-l+1\),那么合法的右端点实际上是由\(i-l[i]+1\)因为,能覆盖到\(l[i]\)这个\(height\)的点实际上是\(l[i]-1\)。)

总之就是比较难理解啊

for (int i=1;i<=n;i++) ans=ans-2ll*(r[i]-i+1)*(i-l[i]+1)*height[i];

那么现在的问题就是应该怎么求\(l[i]和r[i]\)呢?

QWQ这貌似是单调栈的经典应用?

直接从左到右,从右到左扫两遍即可.

这里有一个很好的防止计算重复的方法

就是我们从左到右扫维护的栈是单调的。然后从右到左不单调(非严格)

或者说,一遍单调,一遍不单调,即可解决重复的问题了!

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk makr_pair
#define ll long long
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 2e6+1e2;
struct Node{
int val,pos;
};
int wb[maxn],sa[maxn];
Node s[maxn];
int l[maxn],r[maxn];
int rk[maxn],h[maxn],height[maxn];
int tmp[maxn];
int n,m;
char a[maxn];
int ans;
void getsa()
{
int *x = rk,*y = tmp;
int s = 128;
int p = 0;
for (int i=1;i<=n;i++) x[i]=a[i],y[i]=i;
for (int i=1;i<=s;i++) wb[i]=0;
for (int i=1;i<=n;i++) wb[x[y[i]]]++;
for (int i=1;i<=s;i++) wb[i]+=wb[i-1];
for (int i=n;i>=1;i--) sa[wb[x[y[i]]]--] = y[i];
for (int j=1;p<n;j<<=1)
{
p=0;
for (int i=n-j+1;i<=n;i++) y[++p]=i;
for (int i=1;i<=n;i++) if (sa[i]>j) y[++p]=sa[i]-j;
for (int i=1;i<=s;i++) wb[i]=0;
for (int i=1;i<=n;i++) wb[x[y[i]]]++;
for (int i=1;i<=s;i++) wb[i]+=wb[i-1];
for (int i=n;i>=1;i--) sa[wb[x[y[i]]]--] =y[i];
swap(x,y);
p=1;
x[sa[1]]=1;
for (int i=2;i<=n;i++)
{
x[sa[i]] = (y[sa[i-1]]==y[sa[i]] && y[sa[i]+j]==y[sa[i-1]+j]) ? p : ++p;
}
s=p;
}
for (int i=1;i<=n;i++) rk[sa[i]]=i;
h[0]=0;
for (int i=1;i<=n;i++)
{
h[i]=max(h[i-1]-1,(long long)0);
while (i+h[i]<=n && sa[rk[i]-1]+h[i]<=n && a[i+h[i]]==a[sa[rk[i]-1]+h[i]]) h[i]++;
}
for (int i=1;i<=n;i++) height[i] = h[sa[i]];
}
int top;
signed main()
{
scanf("%s",a+1);
n = strlen(a+1);
getsa();
for (int i=1;i<=n;i++) ans=ans+i*(n-1);
l[1]=1;
s[++top].val=height[1];
s[1].pos=1;
for (int i=2;i<=n;i++)
{
while (top>=1 && s[top].val>=height[i]) top--;
if (!top) l[i]=1;
else l[i]=s[top].pos+1;
s[++top].val=height[i];
s[top].pos=i;
}
memset(s,0,sizeof(s));
top=1;
r[n]=n;
s[top].val=height[n];
s[top].pos=n;
for (int i=n-1;i>=1;i--)
{
while (top>=1 && s[top].val>height[i]) top--;
if (!top) r[i]=n;
else r[i]=s[top].pos-1;
s[++top].val=height[i];
s[top].pos=i;
}
for (int i=1;i<=n;i++) ans=ans-2ll*(r[i]-i+1)*(i-l[i]+1)*height[i];
cout<<ans;
return 0;
}

洛谷4248 AHOI2013差异 (后缀数组SA+单调栈)的更多相关文章

  1. 洛谷P4248 [AHOI2013]差异(后缀自动机求lcp之和)

    题目见此 题解:首先所有后缀都在最后一个np节点,然后他们都是从1号点出发沿一些字符边到达这个点的,所以下文称1号点为根节点,我们思考一下什么时候会产生lcp,显然是当他们从根节点开始一直跳相同节点的 ...

  2. 洛谷P1823 [COI2007] Patrik 音乐会的等待(单调栈+二分查找)

    洛谷P1823 [COI2007] Patrik 音乐会的等待(单调栈+二分查找) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1333275 这个题不是很 ...

  3. bzoj 3238: [Ahoi2013]差异 -- 后缀数组

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MB Description Input 一行,一个字符串S Output 一行,一个 ...

  4. 【BZOJ3238】[Ahoi2013]差异 后缀数组+单调栈

    [BZOJ3238][Ahoi2013]差异 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sample Ou ...

  5. [bzoj3238][Ahoi2013]差异_后缀数组_单调栈

    差异 bzoj-3238 Ahoi-2013 题目大意:求任意两个后缀之间的$LCP$的和. 注释:$1\le length \le 5\cdot 10^5$. 想法: 两个后缀之间的$LCP$和显然 ...

  6. [AHOI2013] 差异 - 后缀数组,单调栈

    [AHOI2013] 差异 Description 求 \(\sum {len(T_i) + len(T_j) - 2 lcp(T_i,T_j)}\) 的值 其中 \(T_i (i = 1,2,... ...

  7. BZOJ 3238: [Ahoi2013]差异 [后缀数组 单调栈]

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2326  Solved: 1054[Submit][Status ...

  8. 洛谷P3763 [TJOI2017]DNA(后缀数组 RMQ)

    题意 题目链接 Sol 这题打死我也不会想到后缀数组的,应该会全程想AC自动机之类的吧 但知道这题能用后缀数组做之后应该就不是那么难了 首先把\(S\)和\(S0\)拼到一起跑,求出Height数组 ...

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

    [bzoj3238][Ahoi2013]差异 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sample Ou ...

随机推荐

  1. 手机端rem简单配置相关

    手机端rem简单配置相关 1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 ...

  2. .Net中异步任务的取消和监控

    相关类型: CancellationTokenSource 主要用来创建或取消令牌 CancellationToken 监听令牌状态,注册令牌取消事件 OperationCanceledExcepti ...

  3. Ansible部署及配置介绍

    原文转自:https://www.cnblogs.com/itzgr/p/10233932.html作者:木二 目录 一 Ansible的安装部署 1.1 PIP方式 1.2 YUM方式 二 Ansi ...

  4. 如何实现CSS限制字数,超出部份显示省略号

    <div style="width:200px; white-space:nowrap;overflow:hidden;text-overflow:ellipsis; border:1 ...

  5. MFC中L, _T(),TEXT,_TEXT区别以及含义

    字符串前面加L表示该字符串是Unicode字符串. _T是一个宏,如果项目使用了Unicode字符集(定义了UNICODE宏),则自动在字符串前面加上L,否则字符串不变.因此,Visual C++里边 ...

  6. NOIP模拟测试17&18

    NOIP模拟测试17&18 17-T1 给定一个序列,选取其中一个闭区间,使得其中每个元素可以在重新排列后成为一个等比数列的子序列,问区间最长是? 特判比值为1的情况,预处理比值2~1000的 ...

  7. container of()函数简介

    在linux 内核编程中,会经常见到一个宏函数container_of(ptr,type,member), 但是当你通过追踪源码时,像我们这样的一般人就会绝望了(这一堆都是什么呀? 函数还可以这样定义 ...

  8. Spring Boot 2.x 之 Spring Data JPA, Hibernate 5

    1. Spring Boot常用配置项 基于Spring Boot 2.0.6.RELEASE 1.1 配置属性类 spring.jpa前缀的相关配置项定义在JpaProperties类中, 1.2 ...

  9. 自己用树莓派做了一个电视盒子,还可以看优酷和cctv

    我刚接触树莓派时间不久,安装过raspberry(树莓派官方系统),ubuntu mate,openelec等系统,openelec是一个电视盒子系统,但是我的用的电视机是一个老式的,老是出现闪屏的问 ...

  10. 【OWASP TOP10】2021年常见web安全漏洞TOP10排行

    [2021]常见web安全漏洞TOP10排行 应用程序安全风险 攻击者可以通过应用程序中许多的不同的路径方式去危害企业业务.每种路径方法都代表了一种风险,这些风险都值得关注. 什么是 OWASP TO ...