I-string_2019牛客暑期多校训练营(第四场)
题意
当a != b且a != rev(b)则认为a串与b串不相等,rev(b)表示b串的反串,例如rev(abcd) = dcba
给出一个串求出该串所有不相等的子串个数
题解
先利用后缀数组求出s#rev(s)的不相等子串个数,再扣掉包含字符‘#’的子串个数,包含‘#’的子串个数为\((len(s)+1)^2\),具体取法为以#及左边任意字符为起点,以#及右边字符为终点构成的串,显然这样能取出所有包含#的子串,且这些子串都不相等。
所以求出来结果是\(ans = \frac{(2len(s)+1)*(2len(s))}{2}- \sum_{i=2}^{2len(s)+1}height[i]-(len(s)+1)^2\), 这样求出来的结果是包含a = rev(b)的,比如s = abac,求出来的结果是\({a,b,c,ab,ba,ac,ca,cab,aba,bac,abac,caba}\),可以看出来除了\({a,b,c,aba}\)这几个回文串,剩余的串都是成对的,那么我们用回文树求出s本质不同的回文串个数加上之前的ans再除以2就是答案了
代码
#include <bits/stdc++.h>
const int mx = 5e5+5;
typedef long long ll;
char str[mx];
int t1[mx], t2[mx], c[mx];
int sa[mx], rank[mx], height[mx];
bool cmp(int *r, int a, int b, int l) {
return r[a] == r[b] && r[a+l] == r[b+l];
}
void da(int n, int m) {
n++;
int i, j, p, *x = t1, *y = t2;
for (i = 0; i < m; i++) c[i] = 0;
for (i = 0; i < n; i++) c[x[i] = str[i]]++;
for (i = 1; i < m; i++) c[i] += c[i-1];
for (i = n-1; i >= 0; i--) sa[--c[x[i]]] = i;
for (j = 1; j <= n; j <<= 1) {
p = 0;
for (i = n-j; i < n; i++) y[p++] = i;
for (i = 0; i < n; i++) if (sa[i] >= j) y[p++] = sa[i] - j;
for (i = 0; i < m; i++) c[i] = 0;
for (i = 0; i < n; i++) c[x[y[i]]]++;
for (i = 1; i < m; i++) c[i] += c[i-1];
for (i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
std::swap(x, y);
p = 1; x[sa[0]] = 0;
for (i = 1; i < n; i++)
x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;
if (p >= n) break;
m = p;
}
int k = 0;
n--;
for (i = 0; i <= n; i++) rank[sa[i]] = i;
for (i = 0; i < n; i++) {
if (k) k--;
j = sa[rank[i]-1];
while (str[i+k] == str[j+k]) k++;
height[rank[i]] = k;
}
}
const int N = 26;
struct pTree {
int Next[mx][N];
int fail[mx];
ll cnt[mx];
ll sum[mx];
int num[mx];
int len[mx];
int S[mx];
int last, n, p, cur, now;
int newnode(int l) {
for (int i = 0; i < N; i++) Next[p][i] = 0;
cnt[p] = num[p] = 0;
len[p] = l;
return p++;
}
void init() {
n = p = 0;
newnode(0);
newnode(-1);
last = 0;
S[n] = -1;
fail[0] = 1;
}
int getFail(int x) {
while (S[n - len[x] - 1] != S[n]) x = fail[x];
return x;
}
bool add(int c) {
S[++n] = c;
cur = getFail(last);
bool flag = false;
if (!Next[cur][c]) {
flag = true;
now = newnode(len[cur] + 2);
fail[now] = Next[getFail(fail[cur])][c];
Next[cur][c] = now;
num[now] = num[fail[now]] + 1;
}
last = Next[cur][c];
cnt[last]++;
return flag;
}
void count() {
for (int i = p-1; i >= 0; i--) cnt[fail[i]] += cnt[i];
}
}tree;
int main() {
scanf("%s", str);
int len = std::strlen(str);
str[len] = '#';
for (int i = len+1; i <= 2*len; i++) str[i] = str[2*len-i];
str[2*len+1] = '\0';
int n = 2*len+1;
da(n, 128);
ll tot = 1LL * (2*len+1) * (2*len+2)/2;
tot -= 1LL * (len+1) * (len+1);
for (int i = 2; i <= n; i++) tot -= height[i];
tree.init();
for (int i = 0; i < len; i++) tree.add(str[i]-'a');
printf("%lld\n", (tot+tree.p-2)/2);
return 0;
}
I-string_2019牛客暑期多校训练营(第四场)的更多相关文章
- 2019牛客暑期多校训练营(第九场)A:Power of Fibonacci(斐波拉契幂次和)
题意:求Σfi^m%p. zoj上p是1e9+7,牛客是1e9: 对于这两个,分别有不同的做法. 前者利用公式,公式里面有sqrt(5),我们只需要二次剩余求即可. 后者mod=1e9,5才 ...
- 2019牛客暑期多校训练营(第一场)A题【单调栈】(补题)
链接:https://ac.nowcoder.com/acm/contest/881/A来源:牛客网 题目描述 Two arrays u and v each with m distinct elem ...
- 2019牛客暑期多校训练营(第一场) B Integration (数学)
链接:https://ac.nowcoder.com/acm/contest/881/B 来源:牛客网 Integration 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 5242 ...
- 2019牛客暑期多校训练营(第一场) A Equivalent Prefixes ( st 表 + 二分+分治)
链接:https://ac.nowcoder.com/acm/contest/881/A 来源:牛客网 Equivalent Prefixes 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/ ...
- 2019牛客暑期多校训练营(第二场)F.Partition problem
链接:https://ac.nowcoder.com/acm/contest/882/F来源:牛客网 Given 2N people, you need to assign each of them ...
- 2019牛客暑期多校训练营(第一场)A Equivalent Prefixes(单调栈/二分+分治)
链接:https://ac.nowcoder.com/acm/contest/881/A来源:牛客网 Two arrays u and v each with m distinct elements ...
- [状态压缩,折半搜索] 2019牛客暑期多校训练营(第九场)Knapsack Cryptosystem
链接:https://ac.nowcoder.com/acm/contest/889/D来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言52428 ...
- 2019牛客暑期多校训练营(第二场)J-Subarray(思维)
>传送门< 前言 这题我前前后后看了三遍,每次都是把网上相关的博客和通过代码认真看了再思考,然并卵,最后终于第三遍也就是现在终于看懂了,其实懂了之后发现其实没有那么难,但是的的确确需要思维 ...
- J-Subarray_2019牛客暑期多校训练营(第二场)
题意 有一个只由1,-1组成的数组,给出所有连续的1所在位置,求满足1的个数大于-1的个数的子区间的数量 题解 参考博客:https://www.cnblogs.com/Yinku/p/1122149 ...
- 2019牛客暑期多校训练营(第一场)-A (单调栈)
题目链接:https://ac.nowcoder.com/acm/contest/881/A 题意:给定两个长度均为n的数组a和b,求最大的p使得(a1,ap)和(b1,bp)等价,等价的定义为其任意 ...
随机推荐
- Python实现淘宝秒杀聚划算自动提醒源码
快来加入群[python爬虫交流群](群号570070796),发现精彩内容. 本实例能够监控聚划算的抢购按钮,在聚划算整点聚的时间到达时发出提醒(音频文件自己定义位置)并自动弹开页面(URL自己定义 ...
- Gridea+GitHub搭建个人博客
某日闲余时间看到一篇介绍Gridea博客平台的文章,大概看了一下觉得此平台还不错,随即自己进入Gridea官网瞅了瞅.哇,这搭建过程也太简单了吧,比Hexo博客搭建要容易很多,而且还有后台管理客户端, ...
- JDK、JRE、JVM之间的区别和联系
JDK : Java Development ToolKit(Java开发工具包).JDK是整个JAVA的核心,包括了Java运行环境(Java Runtime Envirnment),一堆Java工 ...
- 转载 | 如何给网页标题添加icon小图标
打开某一个网页会在浏览器的标签栏处显示该网页的标题和图标,当网页被添加到收藏夹或者书签中时也会出现网页的图标,怎么在网页title左边显示网页的logo图标呢? 方法一(被动式): 制作一个ico格式 ...
- jvisualvm/Jconsole监控WAS中间件
1.登录was控制台https://196.168.119.18:9043/ibm/console/,找到自己的应用程序服务器---java和进程管理---进程定义--JAVA虚拟机,然后配置 通用J ...
- kpm字符串匹配算法
首先是简单的朴素匹配算法 /* * 返回子串t在主串s的位置,若不存在则返回0 */ public static int index(String s, String t) { int i = 0;/ ...
- intellij idea与github整合管理代码
各位看官大家好,博主每每在公司学习新知识写代码时都需要通过U盘带回家来继续每天的学习,觉得这样实在麻烦,于是今天就整合了一下github来完成代码的管理. 开始之前我们需要准备三样东西:1.intel ...
- SQL获取客户端网卡电脑名称等信息
Select SYSTEM_USER 当前用户名, USER_NAME() 当前所有者,db_Name() 当前数据库,@@SPID 当前进程号,(select top 1 FileName from ...
- java高并发系列 - 第25天:掌握JUC中的阻塞队列
这是java高并发系列第25篇文章. 环境:jdk1.8. 本文内容 掌握Queue.BlockingQueue接口中常用的方法 介绍6中阻塞队列,及相关场景示例 重点掌握4种常用的阻塞队列 Queu ...
- ReactJS:最大更新深度超出错误
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside com ...