【BZOJ4560】[NOI2016]优秀的拆分

题面

bzoj

洛谷

题解

考虑一个形如\(AABB\)的串是由两个形如\(AA\)的串拼起来的

那么我们设

\(f[i]\):以位置\(i\)为结尾的形如\(AA\)串的个数

\(g[i]\):以位置\(i\)为开头的形如\(AA\)串的个数

\[\therefore Ans=\sum_{i=1}^nf[i]*g[i+1]
\]

题目的难点转化为求\(f,g\)。

但是,其实我们只要\(O(n^2)\)暴力求一下就有\(95pts\)了,

所以我们接下来考虑最后的\(5pts\)怎么拿:

我们枚举\(A\)的长度\(len\)

将所有位置为\(len\)的倍数的点设为关键点,

则如果一个\(AA\)满足要求

这个\(AA\)必过两个关键点,

那么我们要算的就是相邻两个关键点对答案的贡献:

记相邻两个关键点为\(,i,j\)那么\(j=i+len\)

记\(Lcp=lcp(suf(i), suf(j)),Lcs=lcs(pre(i-1),pre(j-1))\)

那么,如果\(Lcp+Lcs<len\),则不能构成\(AA\)

为什么呢?

相当于这样一种情况:

\[\underbrace{.......i-1}_{Lcs}\;\overbrace{\underbrace{i........}_{Lcp}\;....\underbrace{.......j-1}_{Lcs}}^{len}\;\underbrace{j........}_{Lcp}
\]

这样子是不合法的。

反之,中间两段的\(Lcp,Lcs\)会有交,而我们这个\(A\)串的终点落在中间长度为\(Lcp+Lcs-len+1\)的交上都是可以的

因为这样的话平移一下可以保证紧跟着出现一个不重叠的\(A\)串

又因为串\(A\)起点和终点分别出现的位置是一段区间,所以直接分别在\(f,g\)上差分即可

复杂度是调和级数\(O(nlogn)\)。

具体细节看代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
inline int gi() {
register int data = 0, w = 1;
register char ch = 0;
while (!isdigit(ch) && ch != '-') ch = getchar();
if (ch == '-') w = -1, ch = getchar();
while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
return w * data;
}
const int MAX_N = 3e4 + 5;
char a[MAX_N];
int N, lg[MAX_N], f[MAX_N], g[MAX_N];
struct SuffixArray {
int sa[MAX_N], rnk[MAX_N], lcp[MAX_N];
void buildSA() {
#define cmp(i, j, k) (y[i] == y[j] && y[i + k] == y[j + k])
static int x[MAX_N], y[MAX_N], bln[MAX_N];
memset(sa, 0, sizeof(sa));
memset(rnk, 0, sizeof(rnk));
memset(lcp, 0, sizeof(lcp));
memset(x, 0, sizeof(x));
memset(y, 0, sizeof(y));
memset(bln, 0, sizeof(bln));
int M = 122;
for (int i = 1; i <= N; i++) bln[x[i] = a[i]]++;
for (int i = 1; i <= M; i++) bln[i] += bln[i - 1];
for (int i = N; i >= 1; i--) sa[bln[x[i]]--] = i;
for (int k = 1; k <= N; k <<= 1) {
int p = 0;
for (int i = 0; i <= M; i++) y[i] = 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 = 0; i <= M; i++) bln[i] = 0;
for (int i = 1; i <= N; i++) bln[x[y[i]]]++;
for (int i = 1; i <= M; i++) bln[i] += bln[i - 1];
for (int i = N; i >= 1; i--) sa[bln[x[y[i]]]--] = y[i];
swap(x, y); x[sa[1]] = p = 1;
for (int i = 2; i <= N; i++) x[sa[i]] = cmp(sa[i], sa[i - 1], k) ? p : ++p;
if (p >= N) break;
M = p;
}
for (int i = 1; i <= N; i++) rnk[sa[i]] = i;
for (int i = 1, j = 0; i <= N; i++) {
if (j) j--;
while (a[i + j] == a[sa[rnk[i] - 1] + j]) ++j;
lcp[rnk[i]] = j;
}
}
int st[16][MAX_N];
void buildST() {
memset(st, 63, sizeof(st));
for (int i = 1; i <= N; i++) st[0][i] = lcp[i];
for (int i = 1; i <= 15; i++)
for (int j = 1; j <= N; j++)
st[i][j] = min(st[i - 1][j], st[i - 1][j + (1 << (i - 1))]);
}
int query(int l, int r) {
int _l = l, _r = r;
l = min(rnk[_l], rnk[_r]) + 1, r = max(rnk[_l], rnk[_r]);
int t = lg[r - l + 1];
return min(st[t][l], st[t][r - (1 << t) + 1]);
}
} A, B;
void Sol() {
scanf("%s", a + 1); N = strlen(a + 1);
A.buildSA(), A.buildST();
reverse(&a[1], &a[N + 1]);
B.buildSA(), B.buildST();
memset(f, 0, sizeof(f));
memset(g, 0, sizeof(g));
for (int Len = 1; Len <= N / 2; Len++) {
for (int i = Len, j = i + Len; j <= N; i += Len, j += Len) {
int Lcp = min(A.query(i, j), Len), Lcs = min(B.query(N - i + 2, N - j + 2), Len - 1);
int t = Lcp + Lcs - Len + 1;
if (Lcp + Lcs >= Len) {
g[i - Lcs]++, g[i - Lcs + t]--;
f[j + Lcp - t]++, f[j + Lcp]--;
}
}
}
for (int i = 1; i <= N; i++) f[i] += f[i - 1], g[i] += g[i - 1];
long long ans = 0;
for (int i = 1; i < N; i++) ans += 1ll * f[i] * g[i + 1];
printf("%lld\n", ans);
}
int main () {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
#endif
for (int i = 2; i <= 30000; i++) lg[i] = lg[i >> 1] + 1;
int T; scanf("%d", &T);
while (T--) Sol();
return 0;
}

【BZOJ4560】[NOI2016]优秀的拆分的更多相关文章

  1. [NOI2016]优秀的拆分&&BZOJ2119股市的预测

    [NOI2016]优秀的拆分 https://www.lydsy.com/JudgeOnline/problem.php?id=4650 题解 如果我们能够统计出一个数组a,一个数组b,a[i]表示以 ...

  2. luogu1117 [NOI2016]优秀的拆分

    luogu1117 [NOI2016]优秀的拆分 https://www.luogu.org/problemnew/show/P1117 后缀数组我忘了. 此题哈希可解决95分(= =) 设\(l_i ...

  3. [UOJ#219][BZOJ4650][Noi2016]优秀的拆分

    [UOJ#219][BZOJ4650][Noi2016]优秀的拆分 试题描述 如果一个字符串可以被拆分为 AABBAABB 的形式,其中 A 和 B 是任意非空字符串,则我们称该字符串的这种拆分是优秀 ...

  4. [NOI2016]优秀的拆分(SA数组)

    [NOI2016]优秀的拆分 题目描述 如果一个字符串可以被拆分为 \(AABB\) 的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 \(aabaaba ...

  5. 题解-NOI2016 优秀的拆分

    NOI2016 优秀的拆分 \(T\) 组测试数据.求字符串 \(s\) 的所有子串拆成 \(AABB\) 形式的方案总和. 数据范围:\(1\le T\le 10\),\(1\le n\le 3\c ...

  6. [NOI2016]优秀的拆分 后缀数组

    题面:洛谷 题解: 因为对于原串的每个长度不一定等于len的拆分而言,如果合法,它将只会被对应的子串统计贡献. 所以子串这个限制相当于是没有的. 所以我们只需要对于每个位置i求出f[i]表示以i为开头 ...

  7. [BZOJ]4650: [Noi2016]优秀的拆分

    Time Limit: 30 Sec  Memory Limit: 512 MB Description 如果一个字符串可以被拆分为 AABBAABB 的形式,其中 AA 和 BB 是任意非空字符串, ...

  8. [Noi2016]优秀的拆分

    来自F allDream的博客,未经允许,请勿转载,谢谢. 如果一个字符串可以被拆分为 AABB 的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 aab ...

  9. 【刷题】BZOJ 4650 [Noi2016]优秀的拆分

    Description 如果一个字符串可以被拆分为 AABBAABB 的形式,其中 AA 和 BB 是任意非空字符串,则我们称该字符串的这种拆分是优秀的.例如,对于字符串 aabaabaa,如果令 A ...

随机推荐

  1. c++抽象类,纯虚函数

  2. Cookies、sessionStorage和localStorage解释及区别?

    浏览器的缓存机制提供了可以将用户数据存储在客户端上的方式,可以利用cookie,session等跟服务器端进行数据交互 一.cookie和session Cookie和 session都是用来跟踪浏览 ...

  3. Visual Studio 2017 安装过程问题解决

    VS已经发布了两三天了,我也着手安装,但是折腾了两个晚上,怎么都到不了安装界面(选择模块的界面),各种尝试,各种重启,也并不顶什么卵用~ 后来经过各种查LOG,发现我电脑访问不了https://dow ...

  4. STM32F103 ucLinux开发之三(内核启动后不正常)(完结)

    STM32F103 ucLinux内核没有完全启动 从BOOT跳转到内核后,执行一长段的汇编语言,然后来到startkernel函数,开启C语言之旅. 但是内核输出不正常,如下所示: Linux ve ...

  5. GoBelieve service部署常见问题总结

    问题1: 大家好,我按照文档的步骤编译im时(make install),出现 can't load package: package main: app_route.go:1:1: expected ...

  6. 手机版的百度map封装,使用gps定位

    代码如下,包自己引 包参考 一个百度MAP导航的基础封装 使用的是浏览器调用gps定位 修改了标注的大小 效果如图: 代码...... <!DOCTYPE html> <html&g ...

  7. 深入理解java虚拟机读后总结

    之前看过,很多会遗忘,标记一下,温故知新.(明天的我一定会感谢现在努力的自己. ) 一.运行时数据区域 Java虚拟机管理的内存包括几个运行时数据内存:方法区.虚拟机栈.本地方法栈.堆.程序计数器,其 ...

  8. Linux系统Java环境配置

    1.卸载Linux系统自带的JDK java -version rpm -qa | grep -i java 我们要删除掉自带的JDK环境 rpm -e --nodeps java-1.6.0-ope ...

  9. 在vscode中使用webpack中安装的echarts文件失败,dom获取class名,图表不显示

    所有的东西都是新学的,所以遇到了很多问题: (1)首先,在电脑上已经安装了node的情况下, 在npm中安装echarts:npm install echarts --save mac系统在最前面加上 ...

  10. List和ArrayList

    1.为什么List list = new ArrayList()? 也不是非常夸张的说,一定要用List代替ArrayList接收,只是说这样是良好的编码习惯,便于以后代码可能重构. 首先要明白接口和 ...