博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洛谷 P4248: bzoj 3238: [AHOI2013]差异
阅读量:4489 次
发布时间:2019-06-08

本文共 2566 字,大约阅读时间需要 8 分钟。

题目传送门:。

题意简述:

定义两个字符串 \(S\) 和 \(T\) 的差异 \(\operatorname{diff}(S,T)\) 为这两个串的长度之和减去两倍的这两个串的最长公共前缀的长度。

给定一个字符串,定义从第 \(i\) 个字符开始的后缀为 \(Suf_i\)。

求 \(\sum_{1\le i<j\le n}\operatorname{diff}(Suf_i,Suf_j)\)。

题解:

化简式子,原式等于

\[\begin{align*}&\left(\sum_{1\le i<j\le n}i+j\right)-2\times\sum_{1\le i<j\le n}\operatorname{lcp}(Suf_i,Suf_j)\\=& \frac{n(n-1)(n+1)}{2}-2\times\sum_{1\le i<j\le n}\operatorname{lcp}(Suf_i,Suf_j)\end{align*}\]

所以只要求出后半部分即可。

建立字符串的后缀数组。

考虑 Height 数组的贡献:Height 数组中 [2, n] 内的每一个区间都给答案贡献区间最小值。

套路:每个区间的区间最小值之和,使用单调栈解决。

1 #include 
2 #include
3 4 typedef long long LL; 5 const int MN = 500005; 6 7 int N; 8 char str[MN]; 9 10 int M;11 int rk[MN], rk2[MN], SA[MN], SA2[MN];12 int buk[MN], cnt;13 int Height[MN];14 15 void GetHeight() {16 int k = 0;17 for (int i = 1; i <= N; ++i) {18 if (rk[i] == 1) { k = Height[1] = 0; continue; }19 if (k) --k;20 int j = SA[rk[i] - 1];21 while (i + k <= N && j + k <= N && str[i + k] == str[j + k]) ++k;22 Height[rk[i]] = k;23 }24 }25 26 void Rsort() {27 for (int i = 1; i <= M; ++i) buk[i] = 0;28 for (int i = 1; i <= N; ++i) ++buk[rk[i]];29 for (int i = 1; i <= M; ++i) buk[i] += buk[i - 1];30 for (int i = N; i >= 1; --i) SA[buk[rk[SA2[i]]]--] = SA2[i];31 }32 33 void GetSA() {34 M = 26;35 for (int i = 1; i <= N; ++i) rk[i] = str[i] - 'a' + 1, SA2[i] = i;36 Rsort();37 for (int j = 1; j < N; j <<= 1) {38 int P = 0;39 for (int i = N - j + 1; i <= N; ++i) SA2[++P] = i;40 for (int i = 1; i <= N; ++i) if (SA[i] > j) SA2[++P] = SA[i] - j;41 Rsort();42 rk2[SA[1]] = P = 1;43 for (int i = 2; i <= N; ++i) {44 if (rk[SA[i]] != rk[SA[i - 1]] || rk[SA[i] + j] != rk[SA[i - 1] + j]) ++P;45 rk2[SA[i]] = P;46 }47 for (int i = 1; i <= N; ++i) rk[i] = rk2[i];48 M = P;49 if (M == N) break;50 }51 GetHeight();52 }53 54 int st[MN], t;55 int L[MN], R[MN];56 57 int main() {58 scanf("%s", str + 1);59 N = strlen(str + 1);60 GetSA();61 st[t = 1] = 1;62 for (int i = 2; i <= N; ++i) {63 while (t && Height[st[t]] > Height[i]) R[st[t--]] = i;64 L[i] = st[t];65 st[++t] = i;66 } while (t) R[st[t--]] = N + 1;67 LL Ans = (LL)(N - 1) * N * (N + 1) / 2;68 for (int i = 2; i <= N; ++i)69 Ans -= 2ll * (R[i] - i) * (i - L[i]) * Height[i];70 printf("%lld\n", Ans);71 return 0;72 }

 

转载于:https://www.cnblogs.com/PinkRabbit/p/10124064.html

你可能感兴趣的文章
dubbo+zookeeper注册服务报错问题:No service registed on zookeeper
查看>>
极验滑动验证登录
查看>>
求多个数的质因子
查看>>
laravel的orm作用
查看>>
jQuery插件学习笔记
查看>>
知识梳理HTML篇
查看>>
SQL关键字-exists
查看>>
每天一个linux命令(42):kill命令
查看>>
java获取当前路径的几种方法
查看>>
常用的js函数
查看>>
Unity 碰撞检测 OnTriggerEnter 入门
查看>>
利用DFS求联通块个数
查看>>
总结:
查看>>
将文件写到磁盘
查看>>
spring boot 整合redis --sea 方式1
查看>>
Android Http请求方法汇总
查看>>
缓存技术PK:选择Memcached还是Redis?
查看>>
深度工作:充分使用每一份脑力
查看>>
UVA529 Addition Chains
查看>>
django项目部署在Apache服务器中,静态文件路径的注意点
查看>>