【BZOJ】【3238】【AHOI2013】diff(差异)
题目链接: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(差异)的更多相关文章
- BZOJ 3238: [Ahoi2013]差异 [后缀数组 单调栈]
3238: [Ahoi2013]差异 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2326 Solved: 1054[Submit][Status ...
- bzoj 3238 Ahoi2013 差异
3238: [Ahoi2013]差异 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2357 Solved: 1067[Submit][Status ...
- BZOJ 3238: [Ahoi2013]差异 [后缀自动机]
3238: [Ahoi2013]差异 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2512 Solved: 1140[Submit][Status ...
- bzoj 3238: [Ahoi2013]差异 -- 后缀数组
3238: [Ahoi2013]差异 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 一行,一个字符串S Output 一行,一个 ...
- [BZOJ 3238] [AHOI 2013] 差异 【后缀数组 + 单调栈】
题目链接:BZOJ - 3238 题目分析 显然,这道题就是求任意两个后缀之间的LCP的和,这与后缀数组的联系十分明显. 求出后缀数组后,求出字典序相邻两个后缀的LCP,即 Height 数组. 那么 ...
- 洛谷 P4248: bzoj 3238: [AHOI2013]差异
题目传送门:洛谷 P4248. 题意简述: 定义两个字符串 \(S\) 和 \(T\) 的差异 \(\operatorname{diff}(S,T)\) 为这两个串的长度之和减去两倍的这两个串的最长公 ...
- ●BZOJ 3238 [Ahoi2013]差异
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3238 题解: 后缀数组套路深. 问题转化为求出任意两个后缀的LCP之和 在计算贡献时,各种不 ...
- BZOJ 3238 [Ahoi2013]差异(后缀自动机)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3238 [题目大意] 给出一个串,设T[i]表示从第i位开始的后缀, 求sum(len( ...
- BZOJ 3238: [Ahoi2013]差异 后缀自动机 树形dp
http://www.lydsy.com/JudgeOnline/problem.php?id=3238 就算是全局变量,也不要忘记,初始化(吐血). 长得一副lca样,没想到是个树形dp(小丫头还有 ...
- BZOJ 3238: [Ahoi2013]差异((单调栈+后缀数组)/(后缀树))
[传送门[(https://www.lydsy.com/JudgeOnline/problem.php?id=3238) 解题思路 首先原式可以把\(len\)那部分直接算出来,然后通过后缀数组求\( ...
随机推荐
- [leetcode]_Longest Substring Without Repeating Characters
问题:求一个字符串中最长不重复子串的长度. 直接思路:以每个字符为出发计算最长不重复子串.TLE.O(n2),HashMap存储字符出现的位置. 代码: public int lengthOfLong ...
- javascript中split字符串分割函数
1. var ss=s.split("fs"); for(var i=0;i<ss.length;i++){ 处理每一个ss[i]; } 2. "2:3:4:5&q ...
- Firbird 将可 null 的列更新为 not null
在GOOGLE上搜到2种方法: 第一种是新加一列 C2, 然后 update myTable set C2=原字段,再删除[原字段], 但这种方法有限制,当很多其它表引到此表时,非常麻烦. 第 ...
- C# 平时碰见的问题【1】
1. SqlBulkCopy 可以利用这个类实现快速大批量新增数据的效果, 但在使用过程中发现了一个问题: 无法将数据源中的DateTime类型转换成数据库中的int类型 看起来就是数据列不对应导致的 ...
- WIN8+VS2013编写发布WCF之二(部署)
上文简介了如何建立WCF工程并且调试,下面说一下如何部署. 本文将陆陆续续讲述三种部署方式,随着项目的进展将不断补全. 声明: 用管理员身份打开VS2013,发布前请将程序的.net版本改成与服务器相 ...
- STM32F4_RCC系统时钟配置及描述
Ⅰ.概述 对于系统时钟应该都知道它的作用,就是驱动整个芯片工作的心脏,如果没有了它,就等于人没有了心跳. 对于使用开发板学习的朋友来说,RCC系统时钟这一块知识估计没怎么去配置过,原因在于开发板提供的 ...
- DB2缓冲池、表空间
在DB2中建立表空间得指向该表空间所属缓冲池,否则表空间指向默认缓冲池 1.缓冲池 1.1 创建缓冲池 语法:CREATE BUFFERPOOL <bp_name> SIZE <nu ...
- C# ArrayList的用法总结
C# ArrayList的用法总结 System.Collections.ArrayList类是一个特殊的数组.通过添加和删除元素,就可以动态改变数组的长度. 一.优点 1. 支持自动改变大小的功能 ...
- db2查询锁表
--查询锁表情况,可以获取哪个表被锁,其中agent_id为哪个DB2进程锁了表(db2inst1用户下) select * from sysibmadm.LOCKS_HELD with ur; -- ...
- MySQL使用rand函数实现随机数[转]
如何写一个语句能一下更新几百条MYSQL数据! 需要测试MYSQL数据库,里面有一个上万条数据的数据库,如何写一个PHP文件一下每次更新几百条信息,我都是写一个循环一次更新一条信息,这样我知道用WHI ...