BZOJ 3160 万径人踪灭 解题报告
这个题感觉很神呀。将 FFT 和 Manacher 有机结合在了一起。
首先我们不管那个 “不能连续” 的条件,那么我们就可以求出有多少对字母关于某一条直线对称,然后记 $T_i$ 为关于直线 $i$ 对称的字母对的数量,那么答案(暂记为 $Ans$)就会是:
$$Ans = \sum 2^{T_i}-1$$
在不管那个 “不能连续” 的条件的时候,这个应该是显然的。
怎么算的话,我们弄两次。分别把 $a$ 和 $b$ 当做 $1$,另一个当做 $0$,然后就可以得到一个多项式,将这个多项式平方一下就可以得到所有的 $T_i$ 了,具体用 FFT 实现。
那么我们来管一管这个条件。
我们就可以用 Manacher 求出每一条直线的最长回文半径,然后记 $R_i$ 为直线 $i$ 的最长回文半径,那么实际上的总答案就会是:
$$Ans - \sum R_i$$
然后就做完啦。令 $n$ 为字符串的长度:
时间复杂度 $O(n\log n)$,空间复杂度 $O(n)$。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
#define N 262144 + 5
#define _Mod 1000000007
#define Mod 998244353
#define g 3 int n, len, Inv_len, d, ans, e[][N], Rev[N], A[N], T[N], R[N];
char s[N]; inline int Inc(int u, int v, int p)
{
return u + v - (u + v >= p ? p : );
} inline int power(int u, int v, int p)
{
int res = ;
for (; v; v >>= )
{
if (v & ) res = (LL) res * u % p;
u = (LL) u * u % p;
}
return res;
} inline void FFT_Prepare()
{
for (len = n << ; len != (len & -len); len += (len & -len)) ;
for (int i = len; i > ; i >>= ) d ++;
int w = power(g, (Mod - ) / len, Mod);
int Inv_w = power(w, Mod - , Mod);
Inv_len = power(len, Mod - , Mod);
for (int i = ; i < len; i ++)
{
e[][i] = !i ? : (LL) e[][i - ] * w % Mod;
e[][i] = !i ? : (LL) e[][i - ] * Inv_w % Mod;
for (int j = ; j < d; j ++)
if ((i >> j) & ) Rev[i] += << (d - j - );
}
} inline void FFT(int *p, int op)
{
for (int i = ; i < len; i ++)
if (Rev[i] > i) swap(p[Rev[i]], p[i]);
for (int k = , s = ; k < len; k <<= , s ++)
for (int i = ; i < len; i ++)
{
if (i & k) continue ;
int t = (i & (k - )) << (d - s);
int u = Inc(p[i], (LL) p[i + k] * e[op][t] % Mod, Mod);
int v = Inc(p[i], (LL) (Mod - p[i + k]) * e[op][t] % Mod, Mod);
p[i] = u, p[i + k] = v;
}
} inline void FFT_Work(char key)
{
memset(A, , sizeof(A));
for (int i = ; i < n; i ++)
A[i] = (s[i] == key);
FFT(A, );
for (int i = ; i < len; i ++)
A[i] = (LL) A[i] * A[i] % Mod;
FFT(A, );
for (int i = ; i < len; i ++)
T[i] = Inc(T[i], (LL) A[i] * Inv_len % Mod, Mod);
} inline void Manacher()
{
for (int i = (n << ); i >= ; i --)
s[i] = i & ? s[i >> ] : 'c';
int mx = -, id;
for (int i = ; i <= (n << ); i ++)
{
if (mx > i)
R[i] = min(R[id * - i], mx - i);
else R[i] = ;
for (; i + R[i] <= (n << ) && i - R[i] >= && s[i + R[i]] == s[i - R[i]]; R[i] ++) ;
if (i + R[i] > mx)
mx = i + R[i], id = i;
}
} int main()
{
scanf("%s", s);
n = strlen(s);
FFT_Prepare();
for (char ch = 'a'; ch <= 'b'; ch ++)
FFT_Work(ch);
for (int i = ; i < len; i ++)
{
T[i] = (T[i] + ) >> ;
ans = Inc(ans, power(, T[i], _Mod) - , _Mod);
}
Manacher();
for (int i = ; i <= (n << ); i ++)
ans = Inc(ans, _Mod - R[i] / , _Mod);
printf("%d\n", ans); return ;
}
3160_Gromah
BZOJ 3160 万径人踪灭 解题报告的更多相关文章
- BZOJ 3160: 万径人踪灭 FFT+快速幂+manacher
BZOJ 3160: 万径人踪灭 题目传送门 [题目大意] 给定一个长度为n的01串,求有多少个回文子序列? 回文子序列是指从原串中找出任意个,使得构成一个回文串,并且位置也是沿某一对称轴对称. 假如 ...
- bzoj 3160: 万径人踪灭 manachar + FFT
3160: 万径人踪灭 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 133 Solved: 80[Submit][Status][Discuss] ...
- BZOJ 3160: 万径人踪灭 [fft manacher]
3160: 万径人踪灭 题意:求一个序列有多少不连续的回文子序列 一开始zz了直接用\(2^{r_i}-1\) 总-回文子串 后者用manacher处理 前者,考虑回文有两种对称形式(以元素/缝隙作为 ...
- BZOJ 3160: 万径人踪灭
Description 一个ab串,问有多少回文子序列,字母和位置都对称,并且不连续. Sol FFT+Manacher. 不连续只需要减去连续的就可以了,连续的可以直接Manacher算出来. 其他 ...
- BZOJ 2959: 长跑 解题报告
2959: 长跑 Description 某校开展了同学们喜闻乐见的阳光长跑活动.为了能"为祖国健康工作五十年",同学们纷纷离开寝室,离开教室,离开实验室,到操场参加3000米长跑 ...
- bzoj 3160 万径人踪灭——FFT
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3160 似乎理解加深了. 用卷积算相同的位置:先把 a 赋成1. b 赋成0,卷积一遍:再把 ...
- bzoj 3160 万径人踪灭 FFT
万径人踪灭 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1936 Solved: 1076[Submit][Status][Discuss] De ...
- bzoj 3160 万径人踪灭 —— FFT
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3160 求出关于一个位置有多少对对称字母,如果 i 位置有 f[i] 对,对答案的贡献是 2^ ...
- BZOJ 4238 电压 解题报告
BZOJ 4238 电压 考虑一条边成为答案以后,删去Ta后剩下的图是一个或很多个二分图,即没有奇环 则一条边可以成为答案,当且仅当自己在所有奇环的交上且不在偶环上. 考虑建出dfs树,那么返祖边一定 ...
随机推荐
- CXF(2.7.10) - A simple JAX-WS service
1. 下载 apache-cxf-x.x.x.zip,在工程导入依赖的 jar 包.也可以基于 Maven 构建工程. 2. 定义服务接口. package com.huey.demo.ws; imp ...
- 在 Tomcat 中设置 JDBCRealm
除了默认配置的 DataSourceRealm,Tomcat 还支持 JDBCRealm,它通过 JDBC 来访问记录在关系数据库里的认证信息. JDBCRealm 的配置步骤如下: 在 $TOMCA ...
- ASP多行多列显示代码
<table width="98%" border="0" align="center"> <tr> <% S ...
- 解决MS Office下载网站数据失败的问题
最近遇到在MS Excel中建立的Web Query在创建完成后过了一段时间(或关闭文件后再次打开文件并刷新数据)出现无法刷新的问题,点击刷新时报错如下: 无法下载您要求的信息. 这是一个很不友好的报 ...
- JSP之session
index.jsp: <form id="form1" name="form1" method="post" action=" ...
- sqlserver根据id集合,批量插入。(巧用sqlserver内置函数)
场景如下,传入的id,如1,3,4,88.可以在.net后台处理,但是我更习惯在数据库中操作. 插入数据时可以这样处理,直接贴代码. CREATE PROCEDURE pro_CategorySave ...
- SecureCRT连接虚拟机中的Linux系统(Ubuntu)
最近在学习Linux,看了网上很多SecureCRT连接本地虚拟机当中的Linux系统,很多都是需要设置Linux的配置文件,有点繁琐,所以自己就摸索了一下,把相关操作贴出来分享一下. SecureC ...
- EFFECTIVE JAVA 第十一章 系列化
EFFECTIVE JAVA 第十一章 系列化(将一个对象编码成一个字节流) 74.谨慎地实现Serializable接口 *实现Serializable接口付出的代价就是大大降低了“改变这个类 ...
- Shell 循环读取文件
使用Shell将Windows环境下的文件拷贝到Linux下面的用法. 在linux下,将dos文件格式转换成linux文件格式的用法,vi打开,然后转到命令格式,执行,然后保存,就可以转换成linu ...
- 多进程之间的互斥信号量实现(Linux和windows跨平台)
多线程之间实现互斥操作方式很多种,临界区(Critical Section),互斥量(Mutex),信号量(Semaphore),事件(Event)等方式 其中临界区,互斥量,信号量算是严格意义的实现 ...