[BZOJ3238][Ahoi2013]差异
2016-04-28 12:07
375 查看
[Ahoi2013]差异
DescriptionInput
一行,一个字符串S
Output
一行,一个整数,表示所求值
Sample Input
cacao
Sample Output
54
HINT
2<=N<=500000,S由小写英文字母组成
Solution
利用SAM建出后缀树,在后缀树上dp。
对于后缀树上一个节点ii,考虑它的任意两个儿子son1,son2son1,son2,如果son1,son2son1,son2中有sum[son1],sum[son2]sum[son1],sum[son2]个表示后缀的节点,那么i在后缀树上代表的串就会被作为i在后缀树上代表的串就会被作为LCP计数计数sum[son1]∗sum[son2]sum[son1]*sum[son2]次
Code
#include <bits/stdc++.h> using namespace std; #define rep(i, l, r) for (int i = (l); i <= (r); i++) #define per(i, r, l) for (int i = (r); i >= (l); i--) #define REP(i, n) for (int i = 0; i < (n); i++) #define PER(i, n) for (int i = (n)-1; i; i--) #define MS(_) memset(_, 0, sizeof(_)) #define MP make_pair #define PB push_back typedef long long ll; template<typename T> inline void read(T &x){ x = 0; T f = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); } while (isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); } x *= f; } template<typename T> inline void ckmax(T &a, T b){ if (a < b) a = b; } template<typename T> inline void ckmin(T &a, T b){ if (a > b) a = b; } template<typename T> inline T sqr(T x){ return x * x; } const int MaxN = 1000010; int nxt[MaxN][26], fa[MaxN], d[MaxN], q[MaxN], n; ll sum[MaxN][2], len[MaxN]; char str[MaxN]; bool suf[MaxN]; struct SAM{ int root, last, cnt; SAM(){ root = last = ++cnt; } inline void ins(int c){ int np = ++cnt, p = last; last = np; len[np] = len[p] + 1; sum[np][0] = 1ll; suf[np] = true; for (; p && !nxt[p][c]; nxt[p][c] = np, p = fa[p]); if (!p) fa[np] = root; else if (len[nxt[p][c]] == len[p] + 1) fa[np] = nxt[p][c]; else{ int nq = ++cnt, q = nxt[p][c]; len[nq] = len[p] + 1; memcpy(nxt[nq], nxt[q], sizeof(nxt[q])); fa[nq] = fa[q]; fa[np] = fa[q] = nq; for (; p && nxt[p][c] == q; nxt[p][c] = nq, p = fa[p]); } } inline void build(){ scanf("%s", str+1); n = strlen(str+1); per(i, n, 1) ins(str[i]-'a'); } inline void topsort(){ rep(i, 1, cnt) d[len[i]]++; rep(i, 1, n) d[i] += d[i-1]; per(i, cnt, 1) q[d[len[i]]--] = i; } inline void cal(){ topsort(); per(i, cnt, 1) sum[fa[q[i]]][0] += sum[q[i]][0]; per(i, cnt, 1) sum[fa[q[i]]][1] += sqr(sum[q[i]][0]); } inline void solve(){ ll ans = 0, res = 0; rep(i, 1, n-1) ans += 1ll*(n-i+1)*(n-i) + 1ll*(1+n-i)*(n-i)/2; rep(i, 1, cnt){ if (suf[i]) sum[i][0]--; res += 1ll * ((sqr(sum[i][0]) - sum[i][1]) >> 1) * len[i]; if (suf[i]) res += 1ll * sum[i][0] * len[i], sum[i][0]++; } printf("%lld\n", ans-2*res); } }sam; int main(){ sam.build(); sam.cal(); sam.solve(); return 0; }
相关文章推荐
- Web 服务编程,REST 与 SOAP
- c++第四次上机作业
- [转]curl的详细使用
- C# 两种方法实现HTTP协议迷你服务器
- Unity 服务器时间
- c++杂七杂八的注意点
- 【BZOJ1100】【POI2007】对称轴osi
- java GC机制的一些总结
- Android studio中正确引入so文件的方法
- ZOJ3460 Missile 二分图拆点二分求解
- (BOOL)synchronize立即更新磁盘内容
- 计算机网络(自顶向下方法)
- mysql--学生课程成绩表
- Java报文或者同步的数据有个别乱码情况的处理.
- 学习配置tomcat虚拟主机
- 颜色校正
- C# 利用HttpListener监听处理Http请求
- AsyncTask源码分析
- Mac环境下服务器搭建
- 代码重构 —— 区分代码和数据