传送门

这题……我觉得像我这样的菜鸡选手难以想出来……

题目要求求出一些子序列,使得其关于某个位置是对称的,而且不能是连续一段,求这样的子序列的个数。这个直接求很困难,但是我们可以先求出所有关于某个位置对称的子序列,最后减去子串的个数。

子串个数可以用\(manacher\)求,至于子序列的话,我们假设以第\(i\)位为中心,那么如果两边有\(x\)对相同的字符,那么这个位置对答案的贡献就是\(2^x-1\)或者\(2^(x+1)-1\)。(因为有可能回文串的长度是偶数,也就是不存在中间点)

考虑怎么求\(x_i\)。\(x_i\)的形式可以写成如下的形式:

\[\sum_{j=0}^ic[i-j] == c[i+j]
\]

发现这个式子非常像卷积的形式。那么我们先初始化两个序列,第一个序列是原字符串为‘a’,对应位置为1,第二个是原字符串为'b',对应位置是1,剩下都是0。这样结果就转化为如下形式:

\[\sum_{j=0}^i a(i-j) * a(i+j) + b(i-j) * b(i+j)
\]

然后让他们自己和自己乘起来,结果相加一下,然后因为卷积会重复把元素计算两遍,所以要+1再/2.

这样得到的各项系数就是各项\(x_i\),我们就可以用快速幂计算。算完之后减去\(manacher\)求出的子串个数即可。

看一下代码。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#include<vector>
#include<map>
#include<queue>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
#define fr friend inline
#define y1 poj
#define mp make_pair
#define pr pair<int,int>
#define fi first
#define sc second
#define pb push_back
#define I puts("bug") using namespace std;
typedef long long ll;
const int M = 200005;
const int INF = 1000000009;
const double eps = 1e-7;
const double pi = acos(-1);
const ll mod = 1e9+7; int read()
{
int ans = 0,op = 1;char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
return ans * op;
} struct Comp
{
double x,y;
Comp(){}
Comp(double kx,double ky){x = kx,y = ky;}
fr Comp operator + (const Comp &a,const Comp &b) {return (Comp){a.x + b.x,a.y + b.y};}
fr Comp operator - (const Comp &a,const Comp &b) {return (Comp){a.x - b.x,a.y - b.y};}
fr Comp operator * (const Comp &a,const Comp &b) {return (Comp){a.x * b.x - a.y * b.y,a.y * b.x + a.x * b.y};}
}a[M<<1],b[M<<1],kx,ky; int n,len = 1,L,p[M<<1],rev[M<<1];
char s[M<<1],c[M];
ll tot,d[M<<1],ans; int change()
{
int l = strlen(c),j = 2;
s[0] = '!',s[1] = '#';
rep(i,0,l-1) s[j++] = c[i],s[j++] = '#';
s[j] = '&';
return j;
} void manacher()
{
int l = change(),mx = 1,mid = 1;
rep(i,1,l-1)
{
if(i < mx) p[i] = min(mx - i,p[(mid<<1) - i]);
else p[i] = 1;
while(s[i-p[i]] == s[i+p[i]]) p[i]++;
if(mx < i + p[i]) mid = i,mx = i + p[i];
tot += (p[i] >> 1),tot %= mod;
}
} void fft(Comp *a,int f)
{
rep(i,0,len-1) if(i < rev[i]) swap(a[i],a[rev[i]]);
for(int i = 1;i < len;i <<= 1)
{
Comp omg1(cos(pi / i),f * sin(pi / i));
for(int j = 0;j < len;j += (i << 1))
{
Comp omg(1,0);
rep(k,0,i-1)
{
kx = a[k+j],ky = omg * a[k+j+i];
a[k+j] = kx + ky,a[k+j+i] = kx - ky,omg = omg * omg1;
}
}
}
} ll qpow(ll a,ll b)
{
ll p = 1;
while(b)
{
if(b & 1) p *= a,p %= mod;
a *= a,a %= mod;
b >>= 1;
}
return p;
} int main()
{
scanf("%s",c);
n = strlen(c);
rep(i,0,n-1)
{
if(c[i] == 'a') a[i].x = 1;
else b[i].x = 1;
}
while(len <= n << 1) len <<= 1,L++;
//I;
rep(i,0,len-1) rev[i] = (rev[i>>1] >> 1) | ((i&1) << (L-1));
fft(a,1),fft(b,1);
rep(i,0,len-1) a[i] = a[i] * a[i] + b[i] * b[i];
fft(a,-1);
rep(i,0,len-1) d[i] = ((ll)floor(a[i].x / len + 0.5) + 1) >> 1;
rep(i,0,len-1) ans += (qpow(2,d[i]) - 1),ans %= mod;
manacher(),ans -= tot,ans %= mod;
while(ans < 0) ans += mod;
printf("%lld\n",ans);
return 0;
}

万径人踪灭(FFT+manacher)的更多相关文章

  1. BZOJ 3160: 万径人踪灭 [fft manacher]

    3160: 万径人踪灭 题意:求一个序列有多少不连续的回文子序列 一开始zz了直接用\(2^{r_i}-1\) 总-回文子串 后者用manacher处理 前者,考虑回文有两种对称形式(以元素/缝隙作为 ...

  2. BZOJ3160:万径人踪灭(FFT,Manacher)

    Solution $ans=$回文子序列$-$回文子串的数目. 后者可以用$manacher$直接求. 前者设$f[i]$表示以$i$为中心的对称的字母对数. 那么回文子序列的数量也就是$\sum_{ ...

  3. P4199 万径人踪灭 FFT + manacher

    \(\color{#0066ff}{ 题目描述 }\) \(\color{#0066ff}{输入格式}\) 一行,一个只包含a,b两种字符的字符串 \(\color{#0066ff}{输出格式}\) ...

  4. BZOJ 3160: 万径人踪灭 FFT+快速幂+manacher

    BZOJ 3160: 万径人踪灭 题目传送门 [题目大意] 给定一个长度为n的01串,求有多少个回文子序列? 回文子序列是指从原串中找出任意个,使得构成一个回文串,并且位置也是沿某一对称轴对称. 假如 ...

  5. Luogu4199 万径人踪灭 FFT、Manacher

    传送门 先不考虑”不是连续的一段“这一个约束条件.可以知道:第$i$位与第$j$位相同,可以对第$\frac{i+j}{2}$位置上产生$1$的贡献(如果$i+j$为奇数表明它会对一条缝产生$1$的贡 ...

  6. BZOJ3160 万径人踪灭 【fft + manacher】

    题解 此题略神QAQ orz po神牛 由题我们知道我们要求出: 回文子序列数 - 连续回文子串数 我们记为ans1和ans2 ans2可以用马拉车轻松解出,这里就不赘述了 问题是ans1 我们设\( ...

  7. bzoj 3160: 万径人踪灭【FFT+manacher】

    考虑正难则反,我们计算所有对称子序列个数,再减去连续的 这里减去连续的很简单,manacher即可 然后考虑总的,注意到关于一个中心对称的两点下标和相同(这样也能包含以空位为对称中心的方案),所以设f ...

  8. 洛谷P4199 万径人踪灭(manacher+FFT)

    传送门 题目所求为所有的不连续回文子序列个数,可以转化为回文子序列数-回文子串数 回文子串manacher跑一跑就行了,考虑怎么求回文子序列数 我们考虑,如果$S_i$是回文子序列的对称中心,那么只要 ...

  9. BZOJ3160 万径人踪灭(FFT+manacher)

    容易想到先统计回文串数量,这样就去掉了不连续的限制,变为统计回文序列数量. 显然以某个位置为对称轴的回文序列数量就是2其两边(包括自身)对称相等的位置数量-1.对称有啥性质?位置和相等.这不就是卷积嘛 ...

随机推荐

  1. Wish3D用户必看!模型加载失败原因汇总

    上传到Wish3D的模型加载不出来,作品显示页面漆黑一片,是什么原因? 很有可能是操作过程中的小失误,不妨从以下几点检查.还是不行的请加QQ群(Wish3D交流群3):635725654,@Wish3 ...

  2. NN优化方法对照:梯度下降、随机梯度下降和批量梯度下降

    1.前言 这几种方法呢都是在求最优解中常常出现的方法,主要是应用迭代的思想来逼近.在梯度下降算法中.都是环绕下面这个式子展开: 当中在上面的式子中hθ(x)代表.输入为x的时候的其当时θ參数下的输出值 ...

  3. sql的一些知识_通配符

    like操作符 通配符只能用于字符串查询 % 指任意字符出现任意次数,包括0次,不包括NULL SELECT username,weight,age FROM userinfo WHERE usern ...

  4. WinKawaks使用技巧

    1 关于载入游戏:把游戏的zip文件放到roms目录下.注意不要随意修改文件名!也不要让文件名有中文!例如:"[游戏roms][neogeo]mslugx.zip"改成" ...

  5. project管理之makefile与自己主动创建makefile文件过程

    (风雪之隅 http://www.laruence.com/2009/11/18/1154.html) Linux Makefile自己主动编译和链接使用的环境 想知道到Linux Makefile系 ...

  6. HEVC的參考队列解码

    參考队列是指在进行帧间解码时.P或者B slice所參考的已解码的.位于解码图像缓存中(DPB, decoded picture buffer)中的图像队列,类似h264中的reflist0和refl ...

  7. [GUIDE] How to Setup Ubuntu 16.04 LTS Xenial Xerus for Compiling Android ROMs

    With a new version of Ubuntu comes an update to my guide for setting up a build environment to compi ...

  8. 怎样退出App之前唤醒还有一个App?

    郝萌主倾心贡献,尊重作者的劳动成果,请勿转载. 假设文章对您有所帮助,欢迎给作者捐赠,支持郝萌主,捐赠数额任意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 SDK并没 ...

  9. Mac OS command line TestNG - “Cannot find class in classpath” error

    直接eclipse执行.xml文件可以正确执行 在mac下执行却总报错: [TestNG] [Error] Cannot find class in classpath 最后解决办法,classpat ...

  10. xpath 节点1

    XPath 含有超过 100 个内建的函数.这些函数用于字符串值.数值.日期和时间比较.节点和 QName 处理.序列处理.逻辑值等等. 节点(Node) 在 XPath 中,有七种类型的节点:元素. ...