题目链接

题目大意是问在$S$串中找区间$[i,j]$,在$T$串中找位置$k$,使得$S[i,j]$和$T[1,k]$可以组成回文串,并且$j-i+1>k$,求这样的三元组$(i,j,k)$的个数。

一开始有点懵,但是仔细一想,因为$j-i+1>k$,所以$S[i,j]$中一定包含了回文串后半段的一部分,即$S[i,j]$中一定有后缀是回文串。

如果回文串是$S[x,j]$,则剩余的$S[i,x-1]$与$T[1,k]$应该也能组成回文串。如果将串$S$倒置,则串$S^{'}$上的原$S[i,x-1]$位置与$T[1,k]$应该相同。

所以解题方式应该比较明了,将串$S$倒置,然后求扩展$kmp$,得到串$S^{'}$每个后缀与串$T$的最长公共前缀。然后对串$S^{'}$构建回文自动机。

可以得到串$S^{'}$每个位置作为回文子串的结尾时的回文串个数。然后枚举串$S^{'}$每个位置$i$,以当前位置作为上文中的$x$,然后计算当前位置对答案的贡献。

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + ;
int Next[maxn];
int Ex[maxn];
void getN(char* s1) {//求子串与自身匹配
int i = , j, p, len = strlen(s1);
Next[] = len;
while (i + < len && s1[i] == s1[i + ])
i++;
Next[] = i;
p = ;
for (i = ; i < len; i++) {
if (Next[i - p] + i < Next[p] + p)
Next[i] = Next[i - p];
else {
j = Next[p] + p - i;
if (j < )
j = ;
while (i + j < len && s1[j] == s1[i + j])
j++;
Next[i] = j;
p = i;
}
}
}
void getE(char* s1, char* s2) {//求子串与主串匹配
int i = , j, p, len1 = strlen(s1), len2 = strlen(s2);
while (i < len1 && i < len2 && s1[i] == s2[i])
i++;
Ex[] = i;
p = ;
for (i = ; i < len1; i++) {
if (Next[i - p] + i < Ex[p] + p)
Ex[i] = Next[i - p];
else {
j = Ex[p] + p - i;
if (j < )
j = ;
while (i + j < len1 && j < len2 && s1[i + j] == s2[j])
j++;
Ex[i] = j;
p = i;
}
}
}
struct Palindromic_Tree {
int next[maxn][];//指向的串为当前串两端加上同一个字符构成
int fail[maxn];//fail指针,失配后跳转到fail指针指向的节点
int cnt[maxn]; //表示节点i表示的本质不同的串的个数,最后用count统计
int num[maxn]; //表示节点i表示的最长回文串的最右端点为回文串结尾的回文串个数
int len[maxn];//len[i]表示节点i表示的回文串的长度
int id[maxn];//表示数组下标i在自动机的哪个位置
int S[maxn];
int last;//指向上一个字符所在的节点,方便下一次add
int n; int p;
int newnode(int x) {
for (int i = ; i < ; ++i) next[p][i] = ;
cnt[p] = ; num[p] = ; len[p] = x;
return p++;
}
void init() {//初始化
p = ;
newnode(); newnode(-);
last = ; n = ;
S[n] = -;
fail[] = ;
}
int get_fail(int x) {//失配后找一个最长的
while (S[n - len[x] - ] != S[n]) x = fail[x];
return x;
}
void add(int x) {
S[++n] = x;
int cur = get_fail(last);//通过上一个回文串找这个回文串的匹配位置
if (!next[cur][x]) {//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串
int now = newnode(len[cur] + );//新建节点
id[n - ] = now;
fail[now] = next[get_fail(fail[cur])][x];//建立fail指针,以便失配后跳转
next[cur][x] = now;
num[now] = num[fail[now]] + ;
}
else
id[n - ] = next[cur][x];
last = next[cur][x];
cnt[last]++;
}
void count() {
for (int i = p - ; i >= ; --i) cnt[fail[i]] += cnt[i];
} }a;
char s[maxn], s1[maxn], t[maxn];
int main() {
scanf("%s%s", s, t);
int n = strlen(s), m = strlen(t);
for (int i = ; i < n; i++)
s1[i] = s[n - i - ];
getN(t);
getE(s1, t);
a.init();
for (int i = ; i < n; i++)
a.add(s1[i] - 'a');
a.count();
ll ans = ;
for (int i = n - ; i >= ; i--) {
int w = Ex[i];
ans += 1LL * w * a.num[a.id[i - ]];
}
printf("%lld\n", ans);
}

[gym101981M][2018ICPC南京M题]Mediocre String Problem的更多相关文章

  1. Mediocre String Problem (2018南京M,回文+LCP 3×3=9种做法 %%%千年好题 感谢"Grunt"大佬的细心讲解)

    layout: post title: Mediocre String Problem (2018南京M,回文+LCP 3×3=9种做法 %%%千年好题 感谢"Grunt"大佬的细 ...

  2. ACM-ICPC2018南京赛区 Mediocre String Problem

    Mediocre String Problem 题解: 很容易想到将第一个串反过来,然后对于s串的每个位置可以求出t的前缀和它匹配了多少个(EXKMP 或者 二分+hash). 然后剩下的就是要处理以 ...

  3. Gym - 101981M:(南京) Mediocre String Problem(回文树+exkmp)

    #include<bits/stdc++.h> #define ll long long #define rep(i,a,b) for(int i=a;i<=b;i++) using ...

  4. 2018ACM-ICPC南京区域赛M---Mediocre String Problem【exKMP】【Manacher】

    这题就单独写个题解吧.想了两天了,刚刚问了一个大佬思路基本上有了. 题意: 一个串$S$,一个串$T$,在$S$中选一段子串$S[i,j]$,在$T$中选一段前缀$T[1,k]$使得$S[i,j]T[ ...

  5. Gym - 101981M The 2018 ICPC Asia Nanjing Regional Contest M.Mediocre String Problem Manacher+扩增KMP

    题面 题意:给你2个串(长度1e6),在第一个串里找“s1s2s3”,第二个串里找“s4”,拼接后,是一个回文串,求方案数 题解:知道s1和s4回文,s2和s3回文,所以我们枚举s1的右端点,s1的长 ...

  6. [gym101981D][2018ICPC南京D题]Country Meow

    题目链接 题目大意是求三维空间可以包含$n$个点的最小圆半径. 如果有做过洛谷P1337就会发现这到题很模拟退火,所以就瞎搞一发. $PS:$注意本题时限$3$秒. #include<bits/ ...

  7. hdu String Problem(最小表示法入门题)

    hdu 3374 String Problem 最小表示法 view code#include <iostream> #include <cstdio> #include &l ...

  8. bestcoder 48# wyh2000 and a string problem (水题)

    wyh2000 and a string problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K ...

  9. 2018ICPC南京网络赛

    2018ICPC南京网络赛 A. An Olympian Math Problem 题目描述:求\(\sum_{i=1}^{n} i\times i! \%n\) solution \[(n-1) \ ...

随机推荐

  1. 直接选择排序(Straight Selection Sort)

    1.定义 选择排序(Selection Sort)的基本思想是:每一趟从待排序的记录中选出关键字最小的记录,顺序放在已排好序的子文件的最后,直到全部记录排序完毕. 常用的选择排序方法有直接选择排序和堆 ...

  2. LOJ #6358 前夕 (组合计数、容斥原理)

    题目链接 https://loj.ac/problem/6358 (另外一道\(4\)的倍数题左转loj #6356) 题意 题面写得就像一坨X一样,我来复述一下吧. 有\(N\)个元素构成的集合,要 ...

  3. Oracle根据连续性日期的重复数据取最大或最小值日期

    原始数据: 结果数据: 对比两个图,要是不处理连续性中的重复值,我们直接可以用LEAD函数了事,但处理出来的结果貌似多余. 我的思路是先将原始数据中连续性日期有重复值的处理好,即选择最小的一个,比如2 ...

  4. Apicloud_(项目)网上书城03_拓展模块实现

    Apicloud_(项目)网上书城01_前端页面开发 传送门 Apicloud_(项目)网上书城02_后端数据获取 传送门 Apicloud_(项目)网上书城03_拓展模块实现 传送门 实现商品详情页 ...

  5. PriorityQueue源码阅读

    最小堆:优先级权重越小 离顶点越近 案例 实现一个top max n publish static int[] topN(int[] nums, int l){ int[] result = new ...

  6. ES6 变量的结构赋值

    1.数组的解构赋值 a.基本用法:(‘模糊匹配’) let [a, b, c] = [1, 2, 3]; a b c b.嵌套数组结构例子: let [x, , y] = [1, 2, 3]; x y ...

  7. 构建基于Electron开发的软件遇到的问题

    构建pdman时,报了好些错. 主要还是网络问题和版本不一致导致的. 前提 npm设置淘宝源,自行搜索. 版本 上面是官方要求的node环境. 需要首先安装nvm, brew install nvm ...

  8. SpringBoot启动加载yml配置文件出现编码格式错误

    Caused by: org.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputException: Input l ...

  9. mysql5.6 varchar长度不同的情况下group by的效率

    varchar长度短的情况下,基于这个字段的group by效率更高.所以开发在设计表的时候要使该字段在满足业务需求的情况下尽可能的小. ps:本想找源码看看代码那是怎么处理的,直接用vim看文件太累 ...

  10. SQL server中的一些查询

    SQL 不同于与其他编程语言的最明显特征是处理代码的顺序.在大数编程语言中,代码按编码顺序被处理,但是在SQL语言中,第一个被处理的子句是FROM子句,尽管SELECT语句第一个出现,但是几乎总是最后 ...