BZOJ 3238: [Ahoi2013]差异 (后缀数组+单调栈)

题目要求在这里插入图片描述
所以 A n s = n ∗ ( n − 1 ) ∗ ( n + 1 ) 2 − 2 ∗ ∑ 1 ≤ i &lt; j ≤ n l c p ( T i , T j ) Ans=\frac{n*(n-1)*(n+1)}{2}-2*\sum_{1\le i&lt;j\le n}lcp(T_i, T_j) Ans=2n(n1)(n+1)21i<jnlcp(Ti,Tj)

后面要减去的部分是两两后缀的 l c p lcp lcp,那么做了后缀数组之后就是 A n s = n ∗ ( n − 1 ) ∗ ( n + 1 ) 2 − 2 ∗ ∑ 1 &lt; i ≤ j ≤ n M i n ( H e i g h t i , H e i g h t j ) Ans=\frac{n*(n-1)*(n+1)}{2}-2*\sum_{1&lt;i\le j\le n}Min(Height_i, Height_j) Ans=2n(n1)(n+1)21<ijnMin(Heighti,Heightj)

后面其实就是 [ 2 , n ] [2,n] [2,n]里面所有区间的最小值加起来再乘 2 2 2.

这样我们考虑一个值可以作为最小值能够拓展的最左端和最右端,就可以算出这个值对答案的贡献.这个就单调栈就行了.具体见代码.

…mdzz又双叒叕缀写错后缀(chuo)数组了.

CODE

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 5e5+5;
char s[MAXN];
int n, x[MAXN], y[MAXN], c[MAXN], sa[MAXN], rk[MAXN], ht[MAXN];
inline void Get_Sa(int m) {
    for(int i = 1; i <= m; ++i) c[i] = 0;
    for(int i = 1; i <= n; ++i) ++c[x[i]=s[i]-'a'+1];
    for(int i = 2; i <= m; ++i) c[i] += c[i-1];
    for(int i = n; i >= 1; --i) sa[c[x[i]]--] = i;
    for(int k = 1; k <= n; k<<=1) {
        int p = 0;
        for(int i = n-k+1; i <= n; ++i) y[++p] = i;
        for(int i = 1; i <= n; ++i) if(sa[i]>k) y[++p] = sa[i]-k;
        for(int i = 1; i <= m; ++i) c[i] = 0;
        for(int i = 1; i <= n; ++i) ++c[x[i]];
        for(int i = 2; i <= m; ++i) c[i] += c[i-1];
        for(int i = n; i >= 1; --i) sa[c[x[y[i]]]--] = y[i];
        swap(x, y);
        x[sa[1]] = p = 1;
        for(int i = 2; i <= n; ++i)
            x[sa[i]] = (y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k]) ? p : ++p;
        if((m=p) == n) break;
    }
    for(int i = 1; i <= n; ++i) rk[sa[i]] = i;
}
inline void Get_Ht() {
    for(int i = 1, k = 0, j; i <= n; ++i) if(rk[i] > 1) {
        j = sa[rk[i]-1]; k = k ? k-1 : 0;
        while(i+k <= n && j+k <= n && s[i+k] == s[j+k]) ++k;
        ht[rk[i]] = k;
    }
}
int st[MAXN], top, L[MAXN], R[MAXN];
int main() {
	scanf("%s", s+1);
	n = strlen(s+1);
	Get_Sa(26); Get_Ht();
    L[st[top=1] = 1] = 0;
	for(int i = 2; i <= n; ++i) {
        while(top && ht[st[top]] > ht[i]) R[st[top--]] = i;
        L[i] = st[top]; st[++top] = i;
	}
	while(top) R[st[top--]] = n+1;
    LL ans = 1ll * (n-1) * n * (n+1) / 2;
	for(int i = 2; i <= n; ++i)
        ans -= 2ll * (i-L[i]) * (R[i]-i) * ht[i];
	printf("%lld\n", ans);
}


1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值