[gym101981M][2018ICPC南京M题]Mediocre String Problem
题目大意是问在$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的更多相关文章
- Mediocre String Problem (2018南京M,回文+LCP 3×3=9种做法 %%%千年好题 感谢"Grunt"大佬的细心讲解)
layout: post title: Mediocre String Problem (2018南京M,回文+LCP 3×3=9种做法 %%%千年好题 感谢"Grunt"大佬的细 ...
- ACM-ICPC2018南京赛区 Mediocre String Problem
Mediocre String Problem 题解: 很容易想到将第一个串反过来,然后对于s串的每个位置可以求出t的前缀和它匹配了多少个(EXKMP 或者 二分+hash). 然后剩下的就是要处理以 ...
- 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 ...
- 2018ACM-ICPC南京区域赛M---Mediocre String Problem【exKMP】【Manacher】
这题就单独写个题解吧.想了两天了,刚刚问了一个大佬思路基本上有了. 题意: 一个串$S$,一个串$T$,在$S$中选一段子串$S[i,j]$,在$T$中选一段前缀$T[1,k]$使得$S[i,j]T[ ...
- 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的长 ...
- [gym101981D][2018ICPC南京D题]Country Meow
题目链接 题目大意是求三维空间可以包含$n$个点的最小圆半径. 如果有做过洛谷P1337就会发现这到题很模拟退火,所以就瞎搞一发. $PS:$注意本题时限$3$秒. #include<bits/ ...
- hdu String Problem(最小表示法入门题)
hdu 3374 String Problem 最小表示法 view code#include <iostream> #include <cstdio> #include &l ...
- bestcoder 48# wyh2000 and a string problem (水题)
wyh2000 and a string problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K ...
- 2018ICPC南京网络赛
2018ICPC南京网络赛 A. An Olympian Math Problem 题目描述:求\(\sum_{i=1}^{n} i\times i! \%n\) solution \[(n-1) \ ...
随机推荐
- 通用DES加密解密方法
/// <summary> /// DES加密方法 /// </summary> /// <param name="strPlain">明文&l ...
- POJ 3068 运送危险化学品 最小费用流 模板题
"Shortest" pair of paths Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 1215 ...
- Python3学习笔记(十三):装饰器
装饰器就是一个闭包,它的主要作用是在不改变原函数的基础上对原函数功能进行扩展. 我们先来写一个简单的函数: from time import sleep def foo(): print(" ...
- POJ 6621: K-th Closest Distance(主席树 + 二分)
K-th Closest Distance Time Limit: 20000/15000 MS (Java/Others) Memory Limit: 524288/524288 K (Jav ...
- VS2015 ASP.NET MVC5 EntityFramework6 Oracle 环境篇
//来源:https://www.cnblogs.com/lauer0246/articles/9576940.html Asp.Net MVC EF各版本区别 2009年發行ASP.NET MVC ...
- Java权限管理
基于角色的权限管理
- Shell执行脚本
Shell作用是解释执行用户的命令,用户输入一条命令,Shell就解释执行这一条,这种方式称为交互式,但还有另一种执行命令的方式称为批处理方式,用户事先写一个Shell脚本,Shell可以一次把这些命 ...
- LeetCode 92. 反转链表 II(Reverse Linked List II)
题目描述 反转从位置 m 到 n 的链表.请使用一趟扫描完成反转. 说明: 1 ≤ m ≤ n ≤ 链表长度. 示例: 输入: 1->2->3->4->5->NULL, ...
- JSP——JSTL定制标签 - 递归标签显示属性结构
编写定制标签分为三个步骤:编写标签处理器.配置标签.使用标签. 1.标签处理器 标签处理器和标签是一一对应的关系 package com.oolong.utils.customtags; impo ...
- 为解决Thymeleaf数字格式化问题而想到的几种方案
背景: spring后端输出double类型数据,前端使用thymeleaf框架,格式化double数据类型,由于需要显示原值(比如原来录入5,而不能显示5.00),因此需要存储数值(存储值为deci ...