牛客网多校训练第一场 I - Substring(后缀数组 + 重复处理)
链接:
https://www.nowcoder.com/acm/contest/139/I
题意:
给出一个n(1≤n≤5e4)个字符的字符串s(si ∈ {a,b,c}),
求最多可以从n*(n+1)/2个子串中选出多少个子串,使得它们互不同构。
同构是指存在一个映射f,使得字符串a的每个字符都可以映射成字符串b的对应字符。
例如ab与ac、ba、bc、ca、cb都是同构的。
分析:
以字符串abba为例:
现在只考虑这个字符串的2个子串ab和ba,如果不考虑重构,有2个子串,否则,只有1个子串。
这时,我们可以用全排列枚举出所有重构的字符串:
abba
acca
baab
bccb
caac
cbbc
由于每一个串都有2个子串,所以上面的6个同构串共有12个子串。
如果去掉重复的子串,则最终会剩下6个互不相同的子串。
即第一个字符串abba的ab被第三个字符串baab的ab消掉了,
第二个字符串acca的ac被第五个字符串caac的ac消掉了......
可以发现,剩下的6个子串正是ab的6种同构。
所以我们可以把一个字符串的六种同构拼接在一起,然后用后缀数组求出重复的子串个数height。
为了避免拼接的首尾字符对结果产生影响,要在拼接的每一段后面每次都加上一个新的字符。
设6个同构串的所有子串个数(6*(n*(n+1)/2))为sum。
则(sum-height)/6就是一个字符串里互不重构的子串个数。
但还有一个特殊情况:
只考虑字符串aaabbb的两个子串aaa和bbb。
如果采取上面的做法,最终会留下3个互不相同的子串aaa、bbb和ccc,即重复的子串个数为9。
这时答案是(12-9)/6=0,很显然这样是错误的。
原因是aaa的同构子串只有3种而不是6种,即单一字符的字符串的每个同构串都被多减了一次。
这时,我们可以找出一个字符串里最长的单一字符的字符串str,设它的长度为most。
因为比str短的单一字符的字符串都是str的一部分的重构,所以不需要考虑。
则正确的答案应该是(sum - height + 3*most)/6。(注意例子里aaa的长度视为1而不是3)
代码:
#include <cstdio>
#include <algorithm>
using namespace std; const int MAXS = 1e6 + ;
int sa[MAXS], mem[MAXS], mem2[MAXS], amt[MAXS]; // sa:后缀数组
void build_sa(char* s, int n, int m) { // n:字符串s的长度,每个字符值须小于m
mem[n] = mem2[n] = -;
int i, *x = mem, *y = mem2;
for(i = ; i < m; i++) amt[i] = ;
for(i = ; i < n; i++) amt[x[i]=s[i]]++;
for(i = ; i < m; i++) amt[i] += amt[i-];
for(i = n-; i >= ; i--) sa[--amt[x[i]]] = i;
for(int k = ; k <= n; k <<= ) {
int p = ;
for(i = n-k; i < n; i++) y[p++] = i;
for(i = ; i < n; i++) if(sa[i] >= k) y[p++] = sa[i]-k;
for(i = ; i < m; i++) amt[i] = ;
for(i = ; i < n; i++) amt[x[y[i]]]++;
for(i = ; i < m; i++) amt[i] += amt[i-];
for(i = n-; i >= ; i--) sa[--amt[x[y[i]]]] = y[i];
int* t = x; x = y; y = t;
p = ; x[sa[]] = ;
for(i = ; i < n; i++)
x[sa[i]] = y[sa[i-]]==y[sa[i]]&&y[sa[i-]+k]==y[sa[i]+k]?p-:p++;
if(p >= n) break;
m = p;
}
}
int idx[MAXS], height[MAXS]; // height:sa[i-1]与sa[i]的最长公共前缀
void get_height(char* s, int n) { // n:字符串s的长度
for(int i = ; i < n; i++) idx[sa[i]] = i;
for(int k = , i = ; i < n; i++) {
if(idx[i] - < ) continue;
if(k) k--;
int j = sa[idx[i]-];
while(s[i+k] == s[j+k]) k++;
height[idx[i]] = k;
}
} char s[MAXS], os[MAXS]; int main() {
int n;
while(~scanf("%d%s", &n, os)) {
int p = , en = , a[] = {, , };
do {
for(int i = ; i < n; i++) s[p++] = a[os[i]-'a'];
s[p++] = en++;
} while(next_permutation(a, a+));
build_sa(s, p, );
get_height(s, p);
long long ans = 6LL * n*(n+)/;
for(int i = ; i < p; i++) ans -= height[i];
int most = , len = ;
for(int i = ; i <= n; i++) {
if(os[i] == os[i-]) len++;
else most = max(most, len), len = ;
}
printf("%lld\n", (ans + *most) / );
}
return ;
}
牛客网多校训练第一场 I - Substring(后缀数组 + 重复处理)的更多相关文章
- 牛客网多校训练第一场 J - Different Integers(树状数组 + 问题转换)
链接: https://www.nowcoder.com/acm/contest/139/J 题意: 给出n个整数的序列a(1≤ai≤n)和q个询问(1≤n,q≤1e5),每个询问包含两个整数L和R( ...
- 牛客网多校训练第一场 F - Sum of Maximum(容斥原理 + 拉格朗日插值法)
链接: https://www.nowcoder.com/acm/contest/139/F 题意: 分析: 转载自:http://tokitsukaze.live/2018/07/19/2018ni ...
- 牛客网多校训练第一场 E - Removal(线性DP + 重复处理)
链接: https://www.nowcoder.com/acm/contest/139/E 题意: 给出一个n(1≤n≤1e5)个整数(范围是1至10)的序列,求从中移除m(1≤m≤min(n-1, ...
- 牛客网多校训练第一场 D - Two Graphs
链接: https://www.nowcoder.com/acm/contest/139/D 题意: 两个无向简单图都有n(1≤n≤8)个顶点,图G1有m1条边,图G2有m2条边,问G2有多少个子图与 ...
- 牛客网多校训练第一场 B - Symmetric Matrix(dp)
链接: https://www.nowcoder.com/acm/contest/139/B 题意: 求满足以下条件的n*n矩阵A的数量模m:A(i,j) ∈ {0,1,2}, 1≤i,j≤n.A(i ...
- 牛客网多校训练第一场 A - Monotonic Matrix(Lindström–Gessel–Viennot lemma)
链接: https://www.nowcoder.com/acm/contest/139/A 题意: 求满足以下条件的n*m矩阵A的数量模(1e9+7):A(i,j) ∈ {0,1,2}, 1≤i≤n ...
- 牛客网多校训练第二场D Kth Minimum Clique
链接:https://ac.nowcoder.com/acm/contest/882/D来源:牛客网 Given a vertex-weighted graph with N vertices, fi ...
- 牛客网多校训练第九场H Cutting Bamboos
题目链接:https://ac.nowcoder.com/acm/contest/889/H 题意:给出n颗竹子的高度,q次询问,每次询问给出l,r,x,y,每次选取[l,r]中的竹子,砍y次砍掉所有 ...
- 牛客网多校第3场C-shuffle card 平衡树或stl(rope)
链接:https://www.nowcoder.com/acm/contest/141/C 来源:牛客网 题目描述 Eddy likes to play cards game since there ...
随机推荐
- [转]How to use an Area in ASP.NET Core
本文转自:http://stackoverflow.com/questions/36535511/how-to-use-an-area-in-asp-net-core Q: How does one ...
- JavaScript使用Object.defineProperty方法实现双数据绑定
Object.defineProperty这个方法非常值得学习,很多mvc框架中的双向数据绑定就是通过它来实现的. 本着互联网分享精神,今天我就将我自己的见解分享给大家,希望能有所帮助. 开始使用 O ...
- SQL Server修改表结构,不允许保存更改。
当修改表结构时,sql server会弹出对话框,显示以下内容: 不允许保存更改.您所做的更改要求删除并重新创建以下表.您对无法重新创建的表进行了更改或者启用了“阻止保存要求重新创建表的更改”选项. ...
- jsp、servlet笔记
1.init 初始化Jsp&Servlet方法 destroy 销毁Jsp&Servlet之前的方法 service 对用户请求生成响应的方法2.Jsp文件必须在jsp服 ...
- Spring学习笔记:面向切面编程AOP(Aspect Oriented Programming)
一.面向切面编程AOP 目标:让我们可以“专心做事”,避免繁杂重复的功能编码 原理:将复杂的需求分解出不同方面,将公共功能集中解决 *****所谓面向切面编程,是一种通过预编译方式和运行期动态代理实现 ...
- 静态代码块,构造代码块,main()
静态代码块 随Class 加载而加载,为Class 作初始化: 在main() 之前加载: 只执行一次: 构造代码块 随对象的创建而加载,为对象作初始化 public class day04 { pu ...
- Python-并发编程(线程)
之前我们说了并发编程中的进程问题,几天我们来聊聊并发编程中的线程问题. 一.背景知识 1.进程 之前我们已经了解了操作系统中进程的概念,程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能 ...
- vue-router 的使用
vue-router 是 vue 的 一个特色. 下面介绍vue-router 的使用: 一.先将vue-router作为vue 的一个插件使用 import Vue from 'vue' imp ...
- 任务十:Flexbox 布局练习
任务目的 学习如何flex进行布局,学习如何根据屏幕宽度调整布局策略. 任务描述 需要实现的效果如效果图(点击打开)所示,调整浏览器宽度查看响应式效果,红色的文字是说明,不需要写在 HTML 中. 任 ...
- 求解2的N次幂的问题(多种方法)
#include <iostream> using namespace std; //计算2的N次幂 //一般方法,时间复杂度为2^n __int64 pow2(int n) { __in ...