题目链接:www.lydsy.com/JudgeOnline/problem.php?id=3238

后缀数组

  这题题面给的暗示性就很强啊……一看就是要用后缀xx一家的算法,由于本蒻只会后缀数组所以就拿后缀数组写了。

  

  这个题目的要求……我们很明显可以直接预处理出来T(i)+T(j)的总和,为n*(n-1)*(n+1)/2。(应该挺容易推的吧?自己画一下(样例):当i为1的时候,j可以为2、3、4、5。则1算了4次,2~5各一次;然后2算三次,3~5算一次;3算两次,4、5算一次;4算一次,5算1次。总共加起来,每个数各算了4次。1~5的和是n*(n+1)/2,总共算了(n-1)次,再乘一下就行了。)

  难点在于LCP的减……这个地方我们可以直接在height数组上搞,我们可以发现,每一对(i,j)都对应了height数组上的一段区间、甚至是点!(当i,j两个子串rank相连的时候)那么同样的,每一个height数组上的一段区间(点)也对应我们要求的一个LCP。

  这样有什么好处呢?原本暴力的做法是枚举i,j,用RMQ算LCP,再减;而现在我们转换成直接算LCP,而不用考虑是谁和谁的LCP(事实上并不会落下任何一个),这样问题就简单多了:利用求LCP的特殊性,我们对于每一个height[i],都能找到一段区间[l,r],使得height[i]=min(height[l]~height[r])。额意思就是 i 是[l,r]这个区间上的最小值。这样LCP=height[i]的对数为 (l-i+1)*(r-i+1) 【ps.我们事先说过,[i,i]这样的一个点也算】也就是说我们的答案里可以减去 2*height[i]*(l-i+1)*(r-i+1) 这样一个值。

  但是!!这样会有重复计算的情况:

    举个栗子:height为 1 2 3 1 2 1 1时,第一个1的[l,r]区间为[1,7],第二个为[1,7],明显有重复计算了([l,i] 和 [i,r]这两段有重叠,也就是计算了两次)所以我们在计算对于每个 i 所能到达的[l,r]区间时,遇到相等元素,必须分开处理:比如如果向右遇到相等元素则可以继续扩展,而向左遇到则停止。(当然你反过来做应该也可以……)

  

  现在分析清楚了,最后的问题是:怎么算l[i],r[i],也就是每个height[i]对应的区间?

  这里我们可以利用一个叫做单调栈的东西,维护栈里的元素height[j]都比当前的height[j]要小,如果大则弹出,这样就能O(N)求出所有的l[i],r[i]了。

错误:1.计算答案的时候,必须要在乘法中加上 (LL)类型强制转换,否则会出错。

   2.在栈为空的时候,意味着左边(右边)所有的元素都比当前的要大,则范围应为从端点(1或n)到i的整个区间,而不是i  (见代码)

 /**************************************************************
Problem: 3238
User: ProgrammingApe
Language: C++
Result: Accepted
Time:3416 ms
Memory:23244 kb
****************************************************************/ //练习六 T1 闫鸿宇
//BZOJ 3238
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
using namespace std;
const int N=;
typedef long long LL;
//#define debug
int n,m,sa[N],c[N],wa[N],wb[N],wv[N],rank[N],height[N],l[N],r[N]; int cmp(int *r,int a,int b,int l){
return r[a]==r[b] && r[a+l]==r[b+l];
} void DA(char *s,int *sa,int n,int m){
int i,j,p,*x=wa,*y=wb;
rep(i,m) c[i]=;
rep(i,n) c[x[i]=s[i]]++;
F(i,,m-) c[i]+=c[i-];
D(i,n-,) sa[--c[x[i]]]=i;
for(p=,j=;p<n;j<<=,m=p){
for(p=,i=n-j;i<n;++i) y[p++]=i;
rep(i,n) if (sa[i]>=j) y[p++]=sa[i]-j; rep(i,m) c[i]=;
rep(i,n) c[x[y[i]]]++;
F(i,,m-) c[i]+=c[i-];
D(i,n-,) sa[--c[x[y[i]]]]=y[i];
swap(x,y); p=; x[sa[]]=;
F(i,,n-) x[sa[i]]=cmp(y,sa[i-],sa[i],j) ? p- : p++;
}
} void calheight(char *s,int *sa,int n){
int k=;
F(i,,n) rank[sa[i]]=i;
rep(i,n){
if (k) k--;
int j=sa[rank[i]-];
while(s[i+k]==s[j+k]) k++;
height[rank[i]]=k;
}
} int q[N],st[N],top=;
char s[N];
int main(){
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
scanf("%s",&s);
int n=strlen(s);
rep(i,n) s[i]=s[i]-'a'+;
s[n]=; DA(s,sa,n+,);
calheight(s,sa,n);
height[]=height[n+]=; LL ans=(LL)((LL)n*(n-)*(n+))/,delta=;
//T(i) 和 T(j) 的总和 top=;
st[top++]=;
F(i,,n){
while (top && height[st[top-]] > height[i]) top--;
if (top) l[i]=st[top-]+;
else l[i]=;
st[top++]=i;
} top=;
st[top++]=n; r[n]=n;
D(i,n,){
while (top && height[st[top-]] >= height[i]) top--;
if (top) r[i]=st[top-]-;
else r[i]=n;//!!!!
st[top++]=i;
} #ifdef debug
F(i,,n) printf("%d ",height[i]);
printf("\n");
F(i,,n) printf("%d ",l[i]);
printf("\n");
F(i,,n) printf("%d ",r[i]);
printf("\n");
#endif
F(i,,n){
delta+=(LL)*(LL)height[i]*(LL)(i-l[i]+)*(LL)(r[i]-i+);
#ifdef debug
printf("%d * %d * %d = %d\n",height[i],i-l[i]+,r[i]-i+,height[i]*(i-l[i]+)*(r[i]-i+));
#endif
}
#ifdef debug
printf("%lld %lld\n",ans,delta);
#endif
ans-=delta;
printf("%lld\n",ans);
return ;
}

【BZOJ】【3238】【AHOI2013】diff(差异)的更多相关文章

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

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

  2. bzoj 3238 Ahoi2013 差异

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

  3. BZOJ 3238: [Ahoi2013]差异 [后缀自动机]

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

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

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

  5. [BZOJ 3238] [AHOI 2013] 差异 【后缀数组 + 单调栈】

    题目链接:BZOJ - 3238 题目分析 显然,这道题就是求任意两个后缀之间的LCP的和,这与后缀数组的联系十分明显. 求出后缀数组后,求出字典序相邻两个后缀的LCP,即 Height 数组. 那么 ...

  6. 洛谷 P4248: bzoj 3238: [AHOI2013]差异

    题目传送门:洛谷 P4248. 题意简述: 定义两个字符串 \(S\) 和 \(T\) 的差异 \(\operatorname{diff}(S,T)\) 为这两个串的长度之和减去两倍的这两个串的最长公 ...

  7. ●BZOJ 3238 [Ahoi2013]差异

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3238 题解: 后缀数组套路深. 问题转化为求出任意两个后缀的LCP之和 在计算贡献时,各种不 ...

  8. BZOJ 3238 [Ahoi2013]差异(后缀自动机)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3238 [题目大意] 给出一个串,设T[i]表示从第i位开始的后缀, 求sum(len( ...

  9. BZOJ 3238: [Ahoi2013]差异 后缀自动机 树形dp

    http://www.lydsy.com/JudgeOnline/problem.php?id=3238 就算是全局变量,也不要忘记,初始化(吐血). 长得一副lca样,没想到是个树形dp(小丫头还有 ...

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

    [传送门[(https://www.lydsy.com/JudgeOnline/problem.php?id=3238) 解题思路 首先原式可以把\(len\)那部分直接算出来,然后通过后缀数组求\( ...

随机推荐

  1. [leetcode]_Longest Substring Without Repeating Characters

    问题:求一个字符串中最长不重复子串的长度. 直接思路:以每个字符为出发计算最长不重复子串.TLE.O(n2),HashMap存储字符出现的位置. 代码: public int lengthOfLong ...

  2. javascript中split字符串分割函数

    1. var ss=s.split("fs"); for(var i=0;i<ss.length;i++){ 处理每一个ss[i]; } 2. "2:3:4:5&q ...

  3. Firbird 将可 null 的列更新为 not null

    在GOOGLE上搜到2种方法:   第一种是新加一列 C2, 然后 update myTable set C2=原字段,再删除[原字段], 但这种方法有限制,当很多其它表引到此表时,非常麻烦.   第 ...

  4. C# 平时碰见的问题【1】

    1. SqlBulkCopy 可以利用这个类实现快速大批量新增数据的效果, 但在使用过程中发现了一个问题: 无法将数据源中的DateTime类型转换成数据库中的int类型 看起来就是数据列不对应导致的 ...

  5. WIN8+VS2013编写发布WCF之二(部署)

    上文简介了如何建立WCF工程并且调试,下面说一下如何部署. 本文将陆陆续续讲述三种部署方式,随着项目的进展将不断补全. 声明: 用管理员身份打开VS2013,发布前请将程序的.net版本改成与服务器相 ...

  6. STM32F4_RCC系统时钟配置及描述

    Ⅰ.概述 对于系统时钟应该都知道它的作用,就是驱动整个芯片工作的心脏,如果没有了它,就等于人没有了心跳. 对于使用开发板学习的朋友来说,RCC系统时钟这一块知识估计没怎么去配置过,原因在于开发板提供的 ...

  7. DB2缓冲池、表空间

    在DB2中建立表空间得指向该表空间所属缓冲池,否则表空间指向默认缓冲池 1.缓冲池 1.1 创建缓冲池 语法:CREATE BUFFERPOOL <bp_name> SIZE <nu ...

  8. C# ArrayList的用法总结

    C# ArrayList的用法总结 System.Collections.ArrayList类是一个特殊的数组.通过添加和删除元素,就可以动态改变数组的长度. 一.优点 1. 支持自动改变大小的功能 ...

  9. db2查询锁表

    --查询锁表情况,可以获取哪个表被锁,其中agent_id为哪个DB2进程锁了表(db2inst1用户下) select * from sysibmadm.LOCKS_HELD with ur; -- ...

  10. MySQL使用rand函数实现随机数[转]

    如何写一个语句能一下更新几百条MYSQL数据! 需要测试MYSQL数据库,里面有一个上万条数据的数据库,如何写一个PHP文件一下每次更新几百条信息,我都是写一个循环一次更新一条信息,这样我知道用WHI ...