luogu P4199 万径人踪灭
嘟嘟嘟
方案:回文子序列数 - 回文子串数。
回文子串数用manacher解决就行了,关键是怎么求会问序列数。
一个比较好的\(O(n ^ 2)\)的算法:对于一个回文中心\(i\),\(O(n)\)求出以\(i\)为中心位置对称且字母相同的字母对数\(x\),则以\(i\)为回文中心的回文子序列有\(2 ^ x - 1\)个(排除空序列)。
现在想一下怎么优化。
上面寻找的过程,用一个式子写出来就是这样:
\]
会发现这东西和卷积特别像,但是怎么用多项式表示\(s[i - j] == s[i + j]\)呢?
因为题中说了只有\(a, b\)两种字母,所以构造两个只有\(0\)或\(1\)的多项式\(A, B\),如果\(s[i] = 'a'\),那么\(A(i) = 1\);\(B\)同理。
这样的话式子就变成了
\]
然后两次卷积就行啦。
fft还是不熟……
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define rg register
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const db PI = acos(-1);
const int maxn = 8e5 + 5;
const ll mod = 1e9 + 7;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) last = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
int n, len = 1;
char s[maxn];
struct Comp
{
db x, y;
inline Comp operator + (const Comp& oth)const
{
return (Comp) {x + oth.x, y + oth.y};
}
inline Comp operator - (const Comp& oth)const
{
return (Comp){x - oth.x, y - oth.y};
}
inline Comp operator * (const Comp& oth)const
{
return (Comp){x * oth.x - y * oth.y, x * oth.y + oth.x * y};
}
friend inline void swap(Comp& a, Comp& b)
{
swap(a.x, b.x); swap(a.y, b.y);
}
}a[maxn], b[maxn], omg[maxn], inv[maxn];
void init()
{
omg[0] = inv[0] = (Comp){1, 0};
omg[1] = inv[len - 1] = (Comp){cos(2 * PI / len), sin(2 * PI / len)};
for(int i = 2; i < len; ++i) omg[i] = inv[len - i] = omg[i - 1] * omg[1];
}
void fft(Comp* a, Comp* omg)
{
int lim = 0;
while((1 << lim) < len) lim++;
for(int i = 0; i < len; ++i)
{
int t = 0;
for(int j = 0; j < lim; ++j) if((i >> j) & 1) t |= (1 << (lim - j - 1));
if(i < t) swap(a[i], a[t]);
}
for(int l = 2; l <= len; l <<= 1)
{
int q = l >> 1;
for(Comp* p = a; p != a + len; p += l)
for(int i = 0; i < q; ++i)
{
Comp t = omg[len / l * i] * p[i + q];
p[i + q] = p[i] - t, p[i] = p[i] + t;
}
}
}
char t[maxn << 1];
int p[maxn << 1], m;
void manacher()
{
t[0] = '@';
for(int i = 0; i < n; ++i) t[i << 1 | 1] = '#', t[(i << 1) + 2] = s[i];
m = (n << 1) + 2;
t[m - 1] = '#'; t[m] = '$';
int mx = 0, id;
for(int i = 1; i < m; ++i)
{
if(mx > i) p[i] = min(p[(id << 1) - i], mx - i);
else p[i] = 1;
while(t[i - p[i]] == t[i + p[i]]) p[i]++;
if(i + p[i] > mx) mx = p[i] + i, id = i;
}
}
ll quickpow(ll a, ll b)
{
ll ret = 1;
for(; b; b >>= 1, a = a * a % mod)
if(b & 1) ret = ret * a % mod;
return ret;
}
ll Ans = 0;
int ans[maxn];
int main()
{
scanf("%s", s);
n = strlen(s);
while(len < (n << 1)) len <<= 1;
for(int i = 0 ; i < n; ++i) a[i] = (Comp){s[i] == 'a', 0}, b[i] = (Comp){s[i] == 'b', 0};
init();
fft(a, omg); fft(b, omg);
for(int i = 0; i < len; ++i) a[i] = a[i] * a[i] + b[i] * b[i];
fft(a, inv);
for(int i = 0; i < len; ++i) ans[i] = ((a[i].x / len + 0.5) + 1) / 2;
for(int i = 0; i < len; ++i) Ans = (Ans + quickpow(2, ans[i]) - 1) % mod;
manacher();
for(int i = 1; i < m; ++i) Ans = (Ans - (p[i] >> 1) + mod) % mod;
write(Ans), enter;
return 0;
}
luogu P4199 万径人踪灭的更多相关文章
- 【洛谷】P4199 万径人踪灭
题解 每种字符跑一遍FFT,得到\(i + j = k\)时匹配的个数(要÷2,对于相同位置的最后再加上 然后算出\(2^{cnt[k]}\)的和,最后再减去用mancher匹配出的连续回文子串的个数 ...
- 洛咕 P4199 万径人踪灭
给了两条限制,但是第二条想想是没用的,直接manacher就可以减掉多余的部分了,所以要求满足第一条的方案 也不难,可以想到枚举每个中心点,计算两边有多少对距离中心相等的位置值也相等,假设有\(t\) ...
- P4199 万径人踪灭 FFT + manacher
\(\color{#0066ff}{ 题目描述 }\) \(\color{#0066ff}{输入格式}\) 一行,一个只包含a,b两种字符的字符串 \(\color{#0066ff}{输出格式}\) ...
- 洛谷P4199 万径人踪灭(manacher+FFT)
传送门 题目所求为所有的不连续回文子序列个数,可以转化为回文子序列数-回文子串数 回文子串manacher跑一跑就行了,考虑怎么求回文子序列数 我们考虑,如果$S_i$是回文子序列的对称中心,那么只要 ...
- 2019.2-2019.3 TO-DO LIST
DP P2723 丑数 Humble Numbers(完成时间:2019.3.1) P2725 邮票 Stamps(完成时间:2019.3.1) P1021 邮票面值设计(完成时间:2019.3.1) ...
- FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅰ
众所周知,tzc 在 2019 年(12 月 31 日)就第一次开始接触多项式相关算法,可到 2021 年(1 月 1 日)才开始写这篇 blog. 感觉自己开了个大坑( 多项式 多项式乘法 好吧这个 ...
- Luogu 魔法学院杯-第二弹(萌新的第一法blog)
虽然有点久远 还是放一下吧. 传送门:https://www.luogu.org/contest/show?tid=754 第一题 沉迷游戏,伤感情 #include <queue> ...
- luogu p1268 树的重量——构造,真正考验编程能力
题目链接:http://www.luogu.org/problem/show?pid=1268#sub -------- 这道题费了我不少心思= =其实思路和标称毫无差别,但是由于不习惯ACM风格的题 ...
- 【bzoj3160】【xsy1726】万径人踪灭
[bzoj3160]万径人踪灭 题意 给定一个由'a'和'b'构成的字符串,求不连续回文子序列的个数. \(n\leq 100000\) 分析 还是蛮不错的. 这道题基本上是自己想到的. 除了没有利用 ...
随机推荐
- jstack,jmap,jstat分别的意义
1.Jstack 1.1 jstack能得到运行java程序的java stack和native stack的信息.可以轻松得知当前线程的运行情况.如下图所示 注:这个和thread dump是同 ...
- Differences between write through and write back
https://stackoverflow.com/questions/27087912/write-back-vs-write-through
- AutoFac简介
在.NET上现在存在许多的依赖注入容器, 如:Castle Windsor.StructureMap.Autofac .Unity. 这里主要介绍一下Autofac,Autofac和其他容器的不同之处 ...
- python 字符串居中
下面的代码可以让字符串居中,左对齐和右对齐,字符串长度设置为50,居中后左右补充空格,右对齐会在左侧补充空格 string1 = "Now I am here." print( s ...
- 解决win7无法打开chm格式文件的问题
解决win7无法打开chm格式文件的问题. (一).简单方法(本人用的这个) 1.打开chm2.win7提示安全问题3.chm无法显示内容4.关闭chm5.右键点击chm,点击“解除锁定”,ok 没 ...
- CSS3选择器:nth-child和:nth-of-type之间的差异——张鑫旭
一.深呼吸,直接内容 :nth-child和:nth-of-type都是CSS3中的伪类选择器,其作用近似却又不完全一样,对于不熟悉的人对其可能不是很区分,本文就将介绍两者的不同,以便于大家正确灵活使 ...
- Django基础十之Form和ModelForm组件
一 Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户 ...
- IT小鲜肉 Widgets Tree 单选、多选、相关回调函数、获取选中的节点功能
写一个树控件并没有想象中的那么容易,今天又花了我一个1个多小时,主要为IT小鲜肉 Widgets Tree控件添加了 单选.多选.选择前和选择后两个回调函数.获取选中节点的功能.后面会继续努力完善这个 ...
- 一起来学习android自定义控件—边缘凹凸的View
1前言 最近做项目的时候遇到一个卡劵的效果,由于自己觉得用图片来做的话可以会出现适配效果不好,再加上自己自定义view方面的知识比较薄弱,所以想试试用自定义View来实现.但是由于自己知识点薄弱,一开 ...
- 2018-10-15 00:41:45 c language
2018-10-15 00:41:45 c language C语言输入法的选择 全角和半角的区别主要在于除汉字以外的其它字符,比如标点符号.英文字母.阿拉伯数字等,全角字符和半角字符所占用的位置的 ...