[BZOJ4650][NOI2016]优秀的拆分 各数据点解法
来源:互联网 发布:淘宝卖的七彩小驴 编辑:程序博客网 时间:2024/06/01 22:21
60pts:模拟 O(n4)
直接
此外,注意到前
70pts:哈希 O(n3)
可以发现,判断一个拆分是否合法需要
95pts:分析+哈希 O(n2)
可以想到,如果枚举AA的最后一个字符
以
记以
求
100pts:后缀数组 O(nlogn)
可以看出,
首先枚举AA子串长的一半(记为
此时,先查询子串
这时候,可以看出,
同时,由于这里将AA的左端点限制在了
同样,结果为
感觉NOI2016难度比往年大很多,但暴力分也送的多……
代码:
#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res;}typedef long long ll;const int N = 6e4 + 5, LogN = 18;int w[N], Log[N], le[N], ri[N];struct SA { char s[N]; int n, sa[N], rank[N], height[N], RMQ[N][LogN]; void init() { int *x = rank, *y = height; int i, j, m = 26, k; memset(w, 0, sizeof(w)); memset(rank, 0, sizeof(rank)); for (i = 1; i <= n; i++) w[x[i] = s[i] - 'a' + 1]++; for (i = 2; i <= m; i++) w[i] += w[i - 1]; for (i = 1; i <= n; i++) sa[w[x[i]]--] = i; for (k = 1; k < n; k <<= 1, swap(x, y)) { int tt = 0; for (i = n - k + 1; i <= n; i++) y[++tt] = i; for (i = 1; i <= n; i++) if (sa[i] > k) y[++tt] = sa[i] - k; memset(w, 0, sizeof(w)); for (i = 1; i <= n; i++) w[x[i]]++; for (i = 2; i <= m; i++) w[i] += w[i - 1]; for (i = n; i; i--) sa[w[x[y[i]]]--] = y[i]; m = 0; for (i = 1; i <= n; i++) { int u = sa[i], v = sa[i - 1]; y[u] = x[u] != x[v] || x[u + k] != x[v + k] ? ++m : m; } if (m == n) break; } if (y != rank) copy(y, y + n + 1, rank); height[1] = 0; for (i = 1, k = 0; i <= n; i++) { if (k) k--; int u = sa[rank[i] - 1]; while (s[i + k] == s[u + k]) k++; height[rank[i]] = k; } for (i = 1; i <= n; i++) RMQ[i][0] = height[i]; for (j = 1; j <= 16; j++) for (i = 1; i + (1 << j) - 1 <= n; i++) RMQ[i][j] = min(RMQ[i][j - 1], RMQ[i + (1 << j - 1)][j - 1]); } int lcp(int x, int y) { if (x == y) return n - x + 1; int l = rank[x], r = rank[y], z; if (l > r) swap(l, r); l++; z = Log[r - l + 1]; return min(RMQ[l][z], RMQ[r - (1 << z) + 1][z]); }} S, T;int LCP(int x, int y) { if (x == S.n + 1 || y == S.n + 1) return 0; return S.lcp(x, y);}int LCS(int x, int y) { if (!x || !y) return 0; return T.lcp(T.n - x + 1, T.n - y + 1);}void work() { int i, j, n; scanf("%s", S.s + 1); n = S.n = T.n = strlen(S.s + 1); for (i = n; i; i--) T.s[n - i + 1] = S.s[i]; S.init(); T.init(); memset(le, 0, sizeof(le)); memset(ri, 0, sizeof(ri)); for (i = 1; (i << 1) <= n; i++) for (j = i; j + i <= n; j += i) { int l = min(i - 1, LCS(j - 1, j + i - 1)), r = min(i, LCP(j, j + i)); if (l + r >= i) { le[j - l]++; le[j + r - i + 1]--; ri[j - l + (i << 1) - 1]++; ri[j + r + i]--; } } for (i = 2; i <= n; i++) le[i] += le[i - 1]; for (i = 2; i <= n; i++) ri[i] += ri[i - 1]; ll ans = 0; for (i = 1; i < n; i++) ans += 1ll * ri[i] * le[i + 1]; printf("%lld\n", ans);}int main() { int i, T = read(); Log[0] = -1; for (i = 1; i <= 6e4; i++) Log[i] = Log[i >> 1] + 1; while (T--) work(); return 0;}
- [BZOJ4650][NOI2016]优秀的拆分 各数据点解法
- bzoj4650: [Noi2016]优秀的拆分
- [BZOJ4650][NOI2016]优秀的拆分-后缀数组
- [后缀数组] BZOJ4650: [Noi2016] 优秀的拆分
- 【NOI2016】优秀的拆分
- 4650: [Noi2016]优秀的拆分
- 【后缀数组】[NOI2016]优秀的拆分
- bzoj 4650: [Noi2016]优秀的拆分
- BZOJ 4650([Noi2016]优秀的拆分-SA)
- NOI2016 优秀的拆分 后缀数组
- NOI2016 优秀的拆分 后缀数组
- NOI2016优秀的拆分 后缀数组
- 【NOI2016】优秀的拆分(95分)
- [UOJ P219][NOI2016]优秀的拆分[95]
- Noi2016 D1 T1 优秀的拆分 90做法
- BZOJ 4650: [Noi2016]优秀的拆分 哈希+分块
- UOJ #219 [NOI2016 D1T1] 优秀的拆分 [95分]
- [后缀数组 枚举 字符串分段] BZOJ 4650 [Noi2016]优秀的拆分
- 2017-08-04-log4j-自定义日志器
- java心得(时间API)
- CentOS 7 主机名的修改
- 一图读懂ZStack协议栈的基本架构和工作机理
- redis实现消息队列
- [BZOJ4650][NOI2016]优秀的拆分 各数据点解法
- Python学习【1】
- Two Sum
- 多线程和网络编程
- 12月3日
- Hadoop初识
- 函数与宏
- 拥有csdn博客的第一天
- 【Java 集合】List(ArrayList、Vector、LinkedList)、Map(HashMap、HashTable、LinkedHashMap和TreeMap)