热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

BZOJ3160:万径人踪灭

FFT+Manacher.

FFT+Manacher.



不连续只需要减去连续的就可以了,连续的可以直接Manacher算出来.

其他全部对称的回文子序列就可以用生成函数那样FFT搞出来,把ab分开考虑就行.



有挺多细节的...包括下标运算什么什么的...

/**************************************************************
Problem: 3160
User: BeiYu
Language: C++
Result: Accepted
Time:3868 ms
Memory:29616 kb
****************************************************************/
#include bits/stdc++.h
using namespace std;
#define mpr make_pair
#define rr first
#define ii second
typedef pair double,double Complex;
typedef long long LL;
const int N = 5e5+50;
const long long p = 1e9+7;
const double Pi = M_PI;
Complex operator + (const Complex a,const Complex b) {
return mpr(a.rr+b.rr,a.ii+b.ii);
}
Complex operator - (const Complex a,const Complex b) {
return mpr(a.rr-b.rr,a.ii-b.ii);
}
Complex operator * (const Complex a,const Complex b) {
return mpr(a.rr*b.rr-a.ii*b.ii,a.rr*b.ii+a.ii*b.rr);
int n,l;
LL ans;
int f[N],g[N];
char t[N],s[N];
Complex a[N],b[N],c[N];
LL Pow(LL a,LL b,LL r=1) { for(;b;b =1,a=a*a%p) if(b 1) r=r*a%p;return r; }
void Manacher(char *t) {
int ll=0;
for(int i=0;i i++) s[ll++]='#',s[ll++]=t[i];
s[0]='$',s[ll++]='@';
for(int i=0,j=0,mx=0;i i++) {
if(mx i) f[i]=min(mx-i,f[j*2-i]);else f[i]=1;
while(i+f[i] ll i-f[i] =0 s[i+f[i]]==s[i-f[i]]) f[i]++;
if(i+f[i] mx) mx=i+f[i],j=i;
}
void init(int x) {
for(n=1;n n =1);n =1;
}
void Rev(Complex a[]) {
for(int i=0,j=0;i i++) {
if(i j) swap(a[i],a[j]);
for(int k=n 1;(j^=k) k =1);
}
}
void DFT(Complex a[],int r=1) {
Rev(a);
for(int i=2;i i =1) {
Complex wi=mpr(cos(2.0*Pi/i),r*sin(2.0*Pi/i));
for(int k=0;k k+=i) {
Complex w=mpr(1.0,0.0);
for(int j=k;j k+i/2;j++) {
Complex t1=a[j],t2=w*a[j+i/2];
a[j]=t1+t2,a[j+i/2]=t1-t2;
w=w*wi;
}
}
}
if(r==-1) for(int i=0;i i++) a[i].rr/=n;
}
void FFT(Complex a[],Complex b[],Complex c[]) {
DFT(a),DFT(b);
for(int i=0;i i++) c[i]=a[i]*b[i];
DFT(c,-1);
int main() {
scanf("%s",t);
l=strlen(t);
init(l);
for(int i=0;i i++) a[i]=mpr(t[i]=='a',0),b[i]=a[i];
// reverse(b,b+l);
// for(int i=0;i i++) cout (int)a[i].rr " ";cout endl;
// for(int i=0;i i++) cout (int)b[i].rr " ";cout endl;
FFT(a,b,c);
for(int i=0;i i++) g[i]=(int)(c[i].rr+0.5);
// for(int i=0;i i++) cout (int)(c[i].rr+0.5) " ";cout endl;
memset(a,0,sizeof(a)),memset(b,0,sizeof(b));
for(int i=0;i i++) a[i]=mpr(t[i]=='b',0),b[i]=a[i];
// reverse(b,b+l);
// for(int i=0;i i++) cout (int)a[i].rr " ";cout endl;
// for(int i=0;i i++) cout (int)b[i].rr " ";cout endl;
FFT(a,b,c);
for(int i=0;i i++) g[i]+=(c[i].rr+0.5);
// for(int i=0;i i++) cout (int)(c[i].rr+0.5) " ";cout endl;
for(int i=0;i i++) g[i]=(g[i]+1)/2;
// for(int i=0;i i++) cout g[i] " ";cout endl;
Manacher(t);
// for(int i=0;i i++) cout f[i] " ";cout endl;
for(int i=0;i l*2+1;i++) if(!(i 1)) f[i]-=1;
// for(int i=0;i i++) cout f[i] " ";cout endl;
for(int i=0;i l*2-1;i++) ans=(ans+Pow(2,g[i])-(f[i+1]+1)/2-1)%p;
cout ans endl;
return 0;
}
/*
abaabaa
#bbb#
##aa
53


   



推荐阅读
  • 火星商店问题:线段树分治与持久化Trie树的应用
    本题涉及编号为1至n的火星商店,每个商店有一个永久商品价值v。操作包括每天在指定商店增加一个新商品,以及查询某段时间内某些商店中所有商品(含永久商品)与给定密码值的最大异或结果。通过线段树分治和持久化Trie树来高效解决此问题。 ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 本文探讨了如何在模运算下高效计算组合数C(n, m),并详细介绍了乘法逆元的应用。通过扩展欧几里得算法求解乘法逆元,从而实现除法取余的计算。 ... [详细]
  • Splay Tree 区间操作优化
    本文详细介绍了使用Splay Tree进行区间操作的实现方法,包括插入、删除、修改、翻转和求和等操作。通过这些操作,可以高效地处理动态序列问题,并且代码实现具有一定的挑战性,有助于编程能力的提升。 ... [详细]
  • 题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!-----&# ... [详细]
  • 文件描述符、文件句柄与打开文件之间的关联解析
    本文详细探讨了文件描述符、文件句柄和打开文件之间的关系,通过具体示例解释了它们在操作系统中的作用及其相互影响。 ... [详细]
  • 本文详细探讨了VxWorks操作系统中双向链表和环形缓冲区的实现原理及使用方法,通过具体示例代码加深理解。 ... [详细]
  • 本文详细探讨了KMP算法中next数组的构建及其应用,重点分析了未改良和改良后的next数组在字符串匹配中的作用。通过具体实例和代码实现,帮助读者更好地理解KMP算法的核心原理。 ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • C++: 实现基于类的四面体体积计算
    本文介绍如何使用C++编程语言,通过定义类和方法来计算由四个三维坐标点构成的四面体体积。文中详细解释了四面体体积的数学公式,并提供了两种不同的实现方式。 ... [详细]
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
  • 本文探讨了 C++ 中普通数组和标准库类型 vector 的初始化方法。普通数组具有固定长度,而 vector 是一种可扩展的容器,允许动态调整大小。文章详细介绍了不同初始化方式及其应用场景,并提供了代码示例以加深理解。 ... [详细]
  • 本实验主要探讨了二叉排序树(BST)的基本操作,包括创建、查找和删除节点。通过具体实例和代码实现,详细介绍了如何使用递归和非递归方法进行关键字查找,并展示了删除特定节点后的树结构变化。 ... [详细]
  • 本文详细介绍了C语言中链表的两种动态创建方法——头插法和尾插法,包括具体的实现代码和运行示例。通过这些内容,读者可以更好地理解和掌握链表的基本操作。 ... [详细]
author-avatar
惜洛妍_311
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有