[NOI2016]优秀的拆分 后缀数组
题面:洛谷
题解:
因为对于原串的每个长度不一定等于len的拆分而言,如果合法,它将只会被对应的子串统计贡献。
所以子串这个限制相当于是没有的。
所以我们只需要对于每个位置i求出f[i]表示以i为开头的形如BB这样的串的个数,g[i]表示以i为结尾的形如AA这样的串的个数即可。
考虑分别处理这2个数组。
我们可以枚举AA(BB)这样的串中A(B)的长度l,然后把原串每l个字符放在一个块中,在考虑统计答案。
先考虑这样一个问题:
假如固定一个串的结尾,再枚举这个串A的长度,怎样可以判断是否合法?
实际上我们只需要判断我们假定的这个AA串的开头和中间位置(结尾向前走A的长度)的LCP是否可以覆盖开头到中间即可。
然后如果我们已经把原串对于当前枚举的长度l分成了很多块,其实我们就已经可以对与每个块的开头结尾所代表的点对(i, j)判断是否可以产生贡献了。
但是怎么统计 其他没有刚好对应在某个块的开头结尾的点对 的贡献呢?
表示并没有想出来,,,但是感觉有个blog写的很好,,,
推荐一下:[BZOJ]4650 优秀的拆分(Noi2016)
以后彻底搞懂了再来填坑吧。
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 301000
#define ac 602000
#define LL long long
#define rev reverse
#define mem(x) memset(x, 0, sizeof(x)) int T, n, m;
int h[ac], sa[ac], p1[ac], p2[ac], b[ac], d[ac];
int rk[ac], p[AC], t[AC], rk1[ac];
int st1[AC][], st2[AC][];
int f[AC], g[AC];
LL ans;
char s[AC]; void init()
{
for(R i = ; i <= n; i ++) f[i] = g[i] = rk[i] = ;//因为有多组数据,所以要全部清空
}//mem这么多次还不如for inline void upmax(int &a, int b){
if(b > a) a = b;
} inline int Min(int a, int b){
return (a < b) ? a : b;
} void pre()
{
scanf("%s", s + ), n = strlen(s + ), m = ;
} void ssort()
{
for(R i = ; i <= n; i ++) ++ d[p2[i]];
for(R i = ; i <= m; i ++) d[i] += d[i - ];
for(R i = ; i <= n; i ++) b[d[p2[i]] --] = i;//给i分配d[p2[i]]的排名
for(R i = ; i <= m; i ++) d[i] = ; for(R i = ; i <= n; i ++) ++ d[p1[i]];
for(R i = ; i <= m; i ++) d[i] += d[i - ];
for(R i = n; i; -- i) sa[d[p1[b[i]]] --] = b[i];//给b[i]分配d[p1[b[i]]]的排名
for(R i = ; i <= m; i ++) d[i] = ;
} void get_sa()
{
for(R i = ; i <= n; i ++) sa[i] = i, rk[i] = s[i];//初始化
m = ;//这个也要重置
for(R k = ; k <= n; k <<= )
{
for(R i = ; i <= n; i ++) p1[i] = rk[i], p2[i] = rk[i + k];
ssort();
int tmp = ;
rk[sa[]] = ;
for(R i = ; i <= n; i ++)
rk[sa[i]] = (p1[sa[i]] == p1[sa[i - ]] && p2[sa[i]] == p2[sa[i - ]]) ? tmp : ++ tmp;
if(tmp >= n) break;
m = tmp;//忘了,,,
}
} void build()//获取h数组
{
//memset(h, 0, sizeof(h));
for(R i = , k = ; i <= n; i ++)
{
if(k) -- k;
int j = sa[rk[i] - ];
while(s[i + k] == s[j + k]) ++ k;
h[rk[i]] = k;
}
} #define st st1
void build1()//建st1(维护LCP)
{
int tmp = , cnt = ;
memcpy(rk1, rk, sizeof(rk));
for(R i = ; i <= n; i ++)
{
st[i][] = h[i];
if(i == tmp << ) tmp <<= , ++ cnt;
p[i] = tmp, t[i] = cnt;
}
}
#undef st void build2()//建st2(维护LCS)改成st1, st2一起建了。。。。
{
for(R i = ; i <= n; i ++) st2[i][] = h[i];
int tmp = ;
for(R i = ; i <= ; i ++)
{
for(R j = ; j <= n; j ++)
{
st1[j][i] = Min(st1[j][i - ], st1[j + tmp][i - ]);
st2[j][i] = Min(st2[j][i - ], st2[j + tmp][i - ]);
}
tmp <<= ;
}
} inline void swap(int &l, int &r)
{
int x = l;
l = r, r = x;
} int get1(int l, int r)//查询串l和串r的LCP
{
l = rk1[l], r = rk1[r];
if(l > r) swap(l, r);
++ l;
int len = r - l + ;
return Min(st1[l][t[len]], st1[r - p[len] + ][t[len]]);
} int get2(int l, int r)//查询串l和串r的LCS
{//因为是翻转过来求的,所以查询要翻转一下
l = n - l + , r = n - r + ;
l = rk[l], r = rk[r];
if(l > r) swap(l, r);
++ l;
int len = r - l + ;
return Min(st2[l][t[len]], st2[r - p[len] + ][t[len]]);
} void get()
{
int lim = n << ;
for(R k = ; k < lim; k ++)//枚举A的长度
{
int maxn = , maxn2 = ;
for(R i = ; i <= n; i += k)
{
int j = i + k;//j为下一段开头
if(j > n) break;
if(i > maxn)
{
int lcp = get1(i, j), lcs = get2(i, j);
maxn = i + lcp - ;
int l = i - lcs + , r = j + lcp - * k;
if(lcp + lcs > k) ++ f[l], -- f[r + ];
}
if(i > maxn2)
{
int lcp = get2(n - i + , n - j + ), lcs = get1(n - i + , n - j + );
maxn2 = i + lcp - ;
int l = i - lcs + , r = j + lcp - * k;
if(lcp + lcs > k) ++ g[l], -- g[r + ];
}
}
}
for(R i = ; i <= n; i ++) f[i] += f[i - ], g[i] += g[i - ];
rev(g + , g + n + );
} void work()
{
ans = ;//f是开头
for(R i = ; i <= n; i += )
ans += 1LL * f[i] * g[i - ] + ((i + > n) ? : 1LL * f[i + ] * g[i]);
printf("%lld\n", ans);
} int main()
{
// freopen("in.in", "r", stdin);
scanf("%d", &T);
while(T --)
{
init();
pre();
get_sa();
build();
build1();//建st(维护LCP)
rev(s + , s + n + );//翻转
// memset(rk, 0, sizeof(rk));//因为对于单组数据而言,长度不变,所以rk不必再次清空
get_sa();
build();
build2();//建st2(维护LCS)
get();
work();
}
// fclose(stdin);
return ;
}
[NOI2016]优秀的拆分 后缀数组的更多相关文章
- BZOJ.4650.[NOI2016]优秀的拆分(后缀数组 思路)
BZOJ 洛谷 令\(st[i]\)表示以\(i\)为开头有多少个\(AA\)这样的子串,\(ed[i]\)表示以\(i\)结尾有多少个\(AA\)这样的子串.那么\(Ans=\sum_{i=1}^{ ...
- UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组、ST表)
连NOI Day1T1都不会做...看了题解都写不出来还要抄Claris的代码.. 题目链接: (luogu)https://www.luogu.org/problemnew/show/P1117 ( ...
- BZOJ 4650 [Noi2016]优秀的拆分 ——后缀数组
我们只需要统计在某一个点开始的形如$AA$字符串个数,和结束的个数相乘求和. 首先枚举循环节的长度L.即$\mid (A) \mid=L$ 然后肯定会经过s[i]和[i+L]至少两个点. 然后我们可以 ...
- [NOI2016]优秀的拆分(SA数组)
[NOI2016]优秀的拆分 题目描述 如果一个字符串可以被拆分为 \(AABB\) 的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 \(aabaaba ...
- UOJ#219. 【NOI2016】优秀的拆分 [后缀数组 ST表]
#219. [NOI2016]优秀的拆分 题意:求有多少AABB样子的子串,拆分不同的同一个子串算多个 一开始一直想直接求,并不方便 然后看了一眼Claris的题解的第一行就有思路了 如果分开,求\( ...
- NOI 2016 优秀的拆分 (后缀数组+差分)
题目大意:给你一个字符串,求所有子串的所有优秀拆分总和,优秀的拆分被定义为一个字符串可以被拆分成4个子串,形如$AABB$,其中$AA$相同,$BB$相同,$AB$也可以相同 作为一道国赛题,95分竟 ...
- luogu1117 优秀的拆分 (后缀数组)
考虑分别计算每个位置作为AA的末尾或者BB的开头的个数 最后乘一乘就是答案 据说是套路的计算AA的方法: 首先枚举A的长度L,然后每L个字符当做一个关键点,这样的话,一个AA包含且只包含相邻两个关键点 ...
- [NOI2016]优秀的拆分&&BZOJ2119股市的预测
[NOI2016]优秀的拆分 https://www.lydsy.com/JudgeOnline/problem.php?id=4650 题解 如果我们能够统计出一个数组a,一个数组b,a[i]表示以 ...
- luogu1117 [NOI2016]优秀的拆分
luogu1117 [NOI2016]优秀的拆分 https://www.luogu.org/problemnew/show/P1117 后缀数组我忘了. 此题哈希可解决95分(= =) 设\(l_i ...
随机推荐
- [.NET] 使用HttpClient操作HFS (HTTP File Server)
前言 本篇文章介绍如何使用HttpClient操作HFS (HTTP File Server),为自己留个纪录也希望能帮助到有需要的开发人员.关于HTTP File Server的介绍.安装.设定,可 ...
- XAF.web.NewUI:如何自定义主题
一.使用主题制作工具导出主题: 修改主题生成器工具导出的主题.改完后,导出到 App_Themes 文件夹.例如,更改 ASPxGridView 组面板和Pager面板背景色并保存更改. 使用Them ...
- TensorFlow深度学习实战---循环神经网络
循环神经网络(recurrent neural network,RNN)-------------------------重要结构(长短时记忆网络( long short-term memory,LS ...
- Python环境搭建和pycharm安装
Python环境搭建和pycharm安装 本人安装环境为Windows10系统,下载的Python版本为3.4社区版本,可参考 1.下载Python3.4版本 官网:https://www.pytho ...
- jmeter接口测试实例:带参数、带token
测试内容简介: 1.get请求,无参数 2.get请求,参数为第一条响应中的id 3.get请求,带token 结构图: 下面进行详解: 一.添加cookie管理器等 1.添加ht ...
- windows中使用mysql配置my.ini时的坑
windows中安装mysql的一般步骤: mysql版本:5.7.16 1.解压 2.把解压的文件夹bin目录地址添加到环境变量PATH里面 3.在文件加中添加配置文件my.ini——配置内容后面说 ...
- docker应用容器化准则—12 factor
在云的时代,越来越多的传统应用需要迁移到云环境下,新应用也要求能适应云的架构设计和开发模式.而12-factor提供了一套标准的云原生应用开发的最佳原则. 在容器云项目中应用容器化主要参考12-Fac ...
- AndroidArchitecture
title: AndroidArchitecture date: 2016-04-08 23:26:20 tags: [architecture] categories: [Mobile,Androi ...
- loadrunner socket协议问题归纳(4)---buffer接收变长和定长的数据
测试场景:聊天系统 用户登录后,要先向服务器发送用户名,然后可以发送聊天信息,同时也可以接受聊天信息. 如果接受的字符为定长时,可以设定接受长度.recv buf2 66 #include " ...
- 《英文版c++语言程序设计》
compatibility [kəm,pætɪ'bɪlɪtɪ] n.兼容 compatible [kəm'pætɪb(ə)l] adj. 兼容的:能共处的:可并立的 interdependent [ɪ ...