[SOJ #537]不包含 [CF102129I]Incomparable Pairs(2019-8-6考试)
题目大意:给定一个长度为$n$的字符串$s$,求有多少个无序字符串二元组$(x,y)$满足:$x,y$是$s$的字串,且$x$不是$y$的字串,$y$不是$x$的字串
题解:发现满足$x,y$是$s$字串的二元组很好求,于是转换为求有多少个无序二元组$(x,y)$满足$x$是$y$的字串或$y$是$x$的字串。
对$s$建后缀自动机,对于每一个一个本质不同的子串,计算它包含的本质不同的子串个数之和就是答案。一个子串可能出现多次,任意选取一次就可以计算答案。而对于自动机上的一个节点,它产生的贡献为$s_{min,r},s_{min+1,r},\dots,s_{max,r}$中的本质不同的字串。维护一个数组$p$,令$p_i$表示从$i$开始,到现在$r$的本质不同子串的个数(位置不同的相同子串只记录最后一次),可以对每一个本质不同的字串,在它最后一次出现的左端点$+1$。
每插入一个字符,就算一次新增的自动机节点的贡献,当$r$变大的时候,在$parent$树上从新增节点到根的最后出现位置都会更改。相当于把$parent$树上这一条链染色。
可以用$LCT$,使用$access$操作,每一条重链上的颜色都相等,改变颜色的时候就直接染色,然后改变$p$数组,因为$parent$树上左端点是连续的,所以原来的每条重链可以直接线段树修改。复杂度可以用$LCT$来证,是$O(n\log_2n)$的(可能假了)。
发现我们要求的是后缀和后的区间和,可以在线段树上区间加等差数列。发现$SAM$上节点可能分裂,这里查询答案的时候用原来的大小,查询这个节点原来的$[R-max+1,R-min+1]$。累加就是答案
卡点:写线段树的时候,放标记的时候修改当前节点权值错误,多乘了一个公差;因为调试的时候我枚举所有点放标记答案对了(我也不知道为什么)????导致我后期调试方向出错,白班浪费了$3h+$,还是$little\_gift$一眼指出错误之处
C++ Code:
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- #include <iostream>
- const int maxn = 2e5 + 10;
- int n, pos[maxn];
- char s[maxn];
- int nxt[maxn][26], fail[maxn], R[maxn], mnR[maxn];
- int idx = 1, lst = 1;
- namespace SgT {
- const int N = maxn << 2;
- long long V[N], tg[N], tg2[N];
- inline void addtg(int rt, int len, long long v) {
- V[rt] += v * len;
- tg[rt] += v;
- }
- inline void addtg2(int rt, int len, long long l, long long v) {
- V[rt] += l * len + (len * v) * (len + 1) / 2;
- tg[rt] += l;
- tg2[rt] += v;
- }
- inline void pushdown(int rt, int len) {
- const int L = rt << 1, R = rt << 1 | 1;
- if (tg[rt]) {
- addtg(L, len + 1 >> 1, tg[rt]);
- addtg(R, len >> 1, tg[rt]);
- }
- if (tg2[rt]) {
- addtg2(L, len + 1 >> 1, tg2[rt] * (len >> 1), tg2[rt]);
- addtg2(R, len >> 1, 0, tg2[rt]);
- }
- tg[rt] = tg2[rt] = 0;
- }
- inline void update(int rt) {
- V[rt] = V[rt << 1] + V[rt << 1 | 1];
- }
- void modify(int rt, int l, int r, int L, int R, long long v) {
- if (L <= l && R >= r) {
- addtg(rt, r - l + 1, v);
- return ;
- }
- pushdown(rt, r - l + 1);
- const int mid = l + r >> 1;
- if (L <= mid) modify(rt << 1, l, mid, L, R, v);
- if (R > mid) modify(rt << 1 | 1, mid + 1, r, L, R, v);
- update(rt);
- }
- void modify2(int rt, int l, int r, int L, int R, long long v) {
- if (L <= l && R >= r) {
- const int ll = R - r, len = r - l + 1;
- addtg2(rt, r - l + 1, ll * v, v); // ll + v, ll + 2v, ll + 3v ...
- return ;
- }
- pushdown(rt, r - l + 1);
- const int mid = l + r >> 1;
- if (L <= mid) modify2(rt << 1, l, mid, L, R, v);
- if (R > mid) modify2(rt << 1 | 1, mid + 1, r, L, R, v);
- update(rt);
- }
- void modify(int l, int r, int v) {
- const int len = r - l + 1;
- if (l > 1) modify(1, 1, n, 1, l - 1, len * v);
- if (l > 0 && r >= 1 && l <= r) modify2(1, 1, n, l, r, v);
- }
- long long query(int rt, int l, int r, int L, int R) {
- if (L <= l && R >= r) return V[rt];
- pushdown(rt, r - l + 1);
- const int mid = l + r >> 1;
- long long ans = 0;
- if (L <= mid) ans = query(rt << 1, l, mid, L, R);
- if (R > mid) ans += query(rt << 1 | 1, mid + 1, r, L, R);
- return ans;
- }
- }
- int fa[maxn], son[maxn][2], V[maxn];
- #define lc(rt) son[rt][0]
- #define rc(rt) son[rt][1]
- inline int get(int rt, int tg = 1) { return son[fa[rt]][tg] == rt; }
- inline bool isroot(int rt) { return !(get(rt, 0) || get(rt)); }
- inline void pushdown(int rt) { V[lc(rt)] = V[rc(rt)] = V[rt]; }
- inline void rotate(int x) {
- int y = fa[x], z = fa[y], b = get(x);
- if (!isroot(y)) son[z][get(y)] = x;
- fa[son[y][b] = son[x][!b]] = y, son[x][!b] = y;
- fa[y] = x, fa[x] = z;
- }
- inline void splay(int x) {
- static int S[maxn], top;
- S[top = 1] = x;
- for (int y = x; !isroot(y); S[++top] = y = fa[y]) ;
- for (; top; --top) pushdown(S[top]);
- for (; !isroot(x); rotate(x)) if (!isroot(fa[x]))
- get(x) ^ get(fa[x]) ? rotate(x) : rotate(fa[x]);
- }
- inline void cover(int x, int v) { V[x] = v; }
- inline void access(int x, int v) {
- int t = 0;
- while (x) {
- splay(x), rc(x) = t;
- SgT::modify(V[x] - R[x] + 1, V[x] - R[fa[x]], -1);
- t = x, x = fa[x];
- }
- splay(1), cover(1, v);
- SgT::modify(1, v, 1);
- }
- long long num, ans;
- int append(int ch, int id) {
- static int p, np, q, nq; p = lst, np = lst = ++idx, R[np] = R[p] + 1;
- for (; p && !nxt[p][ch]; p = fail[p]) nxt[p][ch] = np;
- if (!p) fail[np] = 1;
- else {
- q = nxt[p][ch];
- if (R[p] + 1 == R[q]) fail[np] = q;
- else {
- R[nq = ++idx] = R[p] + 1;
- memcpy(nxt[nq], nxt[q], 26 << 2);
- for (; nxt[p][ch] == q; p = fail[p]) nxt[p][ch] = nq;
- fail[nq] = fail[q], fail[q] = fail[np] = nq;
- }
- }
- num += R[np] - R[fail[np]];
- mnR[np] = R[fail[np]] + 1;
- return np;
- }
- int main() {
- std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
- std::cin >> s + 1; n = strlen(s + 1);
- for (int i = 1; i <= n; ++i)
- pos[i] = append(s[i] - 'a', i);
- for (int i = 1; i <= idx; ++i) fa[i] = fail[i];
- for (int i = 1; i <= n; ++i) {
- access(pos[i], i);
- ans += SgT::query(1, 1, n, i - R[pos[i]] + 1, i - mnR[pos[i]] + 1);
- }
- std::cout << (static_cast<unsigned long long> (num + 1) * num - 2 * ans) / 2 << '\n';
- return 0;
- }
[SOJ #537]不包含 [CF102129I]Incomparable Pairs(2019-8-6考试)的更多相关文章
- 【LOJ】#3030. 「JOISC 2019 Day1」考试
LOJ#3030. 「JOISC 2019 Day1」考试 看起来求一个奇怪图形(两条和坐标轴平行的线被切掉了一个角)内包括的点个数 too naive! 首先熟练的转化求不被这个图形包含的个数 -- ...
- 2019.4.1考试&2019.4.2考试&2019.4.4考试
4.1:T1原题,T2码农板子题,T3板子题 4.2 好像是三个出题人分别出的 以及#define *** 傻逼 T1 思维好题 转成树形DP,$dp[i][j]$表示点i值为j的方案数,记录前缀和转 ...
- 2019.3.28&2019.3.30考试
2019.3.28 : 肥肠爆芡,因为这场考试的题太屑了,所以我咕咕了 Upd on 2019.3.30 压进来一篇(因为都没啥意义) 2019.3.30 : 全机房读错题+没有大样例=T2全体爆炸 ...
- 2019.3.18考试&2019.3.19考试&2019.3.21考试
2019.3.18 C O D E T1 树上直接贪心,环上for一遍贪心 哇说的简单,码了将近一下午终于码出来了 感觉自己码力/写题策略太糟糕了,先是搞了一个细节太多的写法最后不得不弃疗了,然后第二 ...
- 2019.2.28&2019.3.1 考试
因为没A/改几道题,就一起写了 题目在LOJ上都能找到 2019.2.28 100+20+12 前两个小时一直在睡觉+想题也没思路,我太菜了 T1 洗衣服 分开处理出洗衣服和烘干的时间,然后一边正着排 ...
- 2019.2.14 考试T3 交互题
\(\color{#0066ff}{ 题目描述 }\) 由于机房被成功拯救了,花_Q很高兴,花_Q生成了一个 0 到 N - 1 的排列(排列的下标从 0 到 N - 1 ).保证排列中 0 在 N ...
- 2019.2.14 考试T1 FFT
\(\color{#0066ff}{ 题目描述 }\) 衡水二中的机房里经常有人莫名其妙地犇雷,leizi很生气,决定要找出那个犇雷的人 机房有n个人,每个人都认为机房里有两个人可能会犇雷,其中第i个 ...
- OCM 12c | OCM 12c Update | OCM 11g (Retiring Dec 31, 2019) | OCM 11g考试延期至2020.04.30
OCM 全球考试安排时间表 View A Worldwide OCM Schedule Oracle Database 12c Certified Master Exam (OCM) OCM 12c ...
- 2019.3.12考试&2019.3.13考试&ESTR
过程:太菜了,不写了 T1 基环树直径,一定学 T2 树上斜率优化,类似购票,数据结构/分治算法,一定改 (把点按深度排序倒着跑2e7次斜率优化也能A,orz zyz) T3 CC原题,码码码,一定补 ...
随机推荐
- 机器学习---逻辑回归(二)(Machine Learning Logistic Regression II)
在<机器学习---逻辑回归(一)(Machine Learning Logistic Regression I)>一文中,我们讨论了如何用逻辑回归解决二分类问题以及逻辑回归算法的本质.现在 ...
- pip崩了, 解决 ModuleNotFoundError: No module named 'pip'.
今天 在windows下用pip 安装数据库模块pymysql 把pip 弄崩了,直接出现下面的错误.都是红字, 再输入pip install pymysql ,会报错ModuleNotFound ...
- coci2011 debt 还债
coci2011 debt 还债 Description 有N个人,每个人恰好欠另一个人Bi元钱,现在大家都没有钱,政府想要给其中一些人欠,使得大家都不欠别人钱. 如A欠B 50,B欠C 20,则当政 ...
- P1270 “访问”美术馆——不太一样的树形DP
P1270 “访问”美术馆 dfs读入,存图有点像线段树: 在枚举时间时,要减去走这条边的代价: #include<cstdio> #include<cstring> #inc ...
- Alapha冲刺(3/6)
队名:無駄無駄 组长博客 作业博客 组员情况 张越洋 过去两天完成了哪些任务 摸鱼 提交记录(全组共用) 接下来的计划 沟通前后端成员,监督.提醒他们尽快完成各自的进度 学习如何评估代码质量 准备Al ...
- Edusoho之X-Auth-Token
昨天这篇文章Edusoho之Basic Authentication提到了X-Auth-Token.今天我主要讲的是Edusoho之X-Auth-Token的请求API方式. 至于为什么建议不要用HT ...
- html 获取项目根路径
html 获取项目根路径 function getContextPath(){ var pathName = document.location.pathname; //当前文件的绝度路径 var i ...
- Springboot属性加载与覆盖优先级与SpringCloud Config Service配置
参考官方文档:https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config. ...
- nodejs 开发时,学用的热更新工具 nodemon
开发用最多的是重启再刷新页面,那热更新少不了, 工具有很多常用唯 nodemon 了, 安装: npm install -g nodemon // 建议全局安装,开发时用的工具 使用: nodemon ...
- 【curl】certificate is bad 问题解决
参考:https://blog.scottlowe.org/2018/08/20/troubleshooting-tls-certificates/ 我最近正在写一篇博客文章,内容涉及使用TLS证书进 ...