bzoj 3160: 万径人踪灭 manachar + FFT

3160: 万径人踪灭

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 133  Solved: 80
[Submit][Status][Discuss]

Description

Input

Output

Sample Input

Sample Output

HINT

  以每一个位置为中心,分别处理连续一块的回文串,回文序列个数。

  比较容易看出是FFT+manachar,但是FFT还是不太熟悉,特别要注意三层for语句中i,j,k不能写错,这东西很难调试出来。

  另外一点就是manachar加‘#’最好头尾都加,要不然第一个,最后一个字符回文串长度会出问题。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define MAXN 610000
#define MOD 1000000007
typedef long long qword;
typedef double real;
const real pi=acos(-1);
struct Complex
{
        real x,y;
        Complex(real x,real y=0):x(x),y(y){}
        Complex(){}
};
Complex operator +(Complex c1,Complex c2)
{
        return Complex(c1.x+c2.x,c1.y+c2.y);
}
Complex operator -(Complex c1,Complex c2)
{
        return Complex(c1.x-c2.x,c1.y-c2.y);
}
Complex operator *(Complex c1,Complex c2)
{
        return Complex(c1.x*c2.x-c1.y*c2.y,c1.x*c2.y+c1.y*c2.x);
}
Complex operator /(Complex c1,real x)
{
        return Complex(c1.x/x,c1.y/x);
}
Complex g1[MAXN],g2[MAXN],g3[MAXN];
Complex gt[MAXN];
void FFT(Complex gg[],int l,int pp)
{
        memcpy(gt,gg,sizeof(gt[0])*l);
        int x;
        for (int i=0;i<l;i++)
        {
                x=0;
                for (int j=1,k=l>>1;j<l;j<<=1,k>>=1)
                        if (i&j)x+=k;
                gg[i]=gt[x];
        }
        Complex w;
        Complex wn;
        Complex tmp;
        for (int i=1;i<l;i<<=1)
        {
                wn=Complex(cos(pi/i*pp),sin(pi/i*pp));
                for (int j=0;j<l;j+=(i<<1))
                {
                        w=Complex(1,0);
                        for (int k=0;k<i;k++)
                        {
                                tmp=gg[j+k];
                                gg[j+k]=gg[j+k]+gg[i+j+k]*w;
                                gg[i+j+k]=tmp-w*gg[i+j+k];
                                w=w*wn;
                        }
                }
        }
}
qword pow_mod(qword x,qword y)
{
        qword ret=1;
        while (y)
        {
                if (y&1)ret=ret*x%MOD;
                x=x*x%MOD;
                y>>=1;
        }
        return ret;
}
char str[MAXN];
char str2[MAXN];
int plen[MAXN];
int plen2[MAXN];
void manachar(int l)
{
        int id=-1,mx=0;
        for (int i=0;i<l;i++)
        {
                if (mx>i)
                        plen[i]=min(mx-i,plen[id*2-i]);
                while (i-plen[i]-1>=0 && i+plen[i]+1<l && str2[i-plen[i]-1]==str2[i+plen[i]+1])
                        plen[i]++;
                if (i+plen[i]>mx)
                {
                        mx=i+plen[i];
                        id=i;
                }
        }
}
qword mi2[MAXN];
int main()
{
        freopen("input.txt","r",stdin);
        int n,m;
        int x,y;
        int l;
        scanf("%s",str);
        n=strlen(str);
        l=n*2+1;
        mi2[0]=1;
        for (int i=1;i<=l;i++)mi2[i]=mi2[i-1]*2%MOD;
        for (int i=0;i<n*2+1;i++)
                str2[i]=‘#‘;
        for (int i=0;i<n;i++)
        {
                if (str[i]==‘a‘)
                {
                        g1[i*2+1]=g2[i*2+1]=1;
                        str2[i*2+1]=‘a‘;
                }else
                {
                        g1[i*2+1]=g2[i*2+1]=-1;
                        str2[i*2+1]=‘b‘;
                }
        }
        manachar(l);
        for (l=n*2;l!=(l&(-l));l-=l&(-l));
        l<<=2;
        FFT(g1,l,1);
        FFT(g2,l,1);
        for (int i=0;i<l;i++)g3[i]=g1[i]*g2[i];
        FFT(g3,l,-1);
        for (int i=0;i<l;i++)g3[i]=g3[i]/l;
        l=n*2;
        for (int i=0;i<l;i++)plen[i]++;
        qword ans=0;
        for (int i=0;i<l;i++)
                plen2[i]=((min(i,l-i-1)+1)+round(g3[i*2].x))/2;
        for (int i=0;i<l;i++)plen2[i]=(plen2[i]+1)/2;
        for (int i=0;i<l;i++)plen[i]=plen[i]/2;
        for (int i=0;i<l;i++)
                ans=(ans+mi2[plen2[i]]-1-plen[i])%MOD;
        printf("%lld\n",ans);
        return 0;
}
时间: 2024-10-23 07:50:16

bzoj 3160: 万径人踪灭 manachar + FFT的相关文章

【BZOJ 3160】 3160: 万径人踪灭 (FFT)

3160: 万径人踪灭 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1440  Solved: 799 Description Input Output Sample Input Sample Output HINT Source 2013湖北互测week1 [分析] 看题目被吓死,其实很多废话.. 还是自己想出来了..FFT好强啊..可以加速很多东西的说. 然后就是,枚举对称轴吧? 假设a[i]==a[j],那么用i+j表示它的对称轴. 共有

BZOJ 3160 万径人踪灭 FFT+Manacher

题意:链接 方法: FFT+Manacher 解析: 对于一个序列,求以任意位置(可以为间隙)为轴对称的不连续回文序列. 我们不妨举一个栗子. 然后我们发现,如果以图中的红线为对称轴的话,那么他的最长回文长度为3,也就是可非连续回文半径为3. 所以大情况下这个对答案的贡献是 C13+C23+C33=23?1 但是其中如图所示有一些不合法的选取. 也就是对于轴来说我们选取了连续,无断点的一段. 我们要把这部分减掉. 然而这部分恰好是以红线为轴的最长连续回文串的半径. 捋一下思路. 首先我们求出所有

[BZOJ 3160] 万径人踪灭

题意 给定一个长度为 n , 由 'a', 'b' 组成的字符串 S . 问有多少个子序列, 满足: ① 坐标对称. ② 字符对称. ③ 不连续. n <= 100000 . 分析 坐标对称, 则要满足对应坐标的值相同. 满足①② 的所有用 FFT 求. 满足①②!③ 的所有用 Manacher 求. 实现 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cc

BZOJ 3160 万径人踪灭 解题报告

这个题感觉很神呀.将 FFT 和 Manacher 有机结合在了一起. 首先我们不管那个 “不能连续” 的条件,那么我们就可以求出有多少对字母关于某一条直线对称,然后记 $T_i$ 为关于直线 $i$ 对称的字母对的数量,那么答案(暂记为 $Ans$)就会是: $$Ans = \sum 2^{T_i}-1$$ 在不管那个 “不能连续” 的条件的时候,这个应该是显然的. 怎么算的话,我们弄两次.分别把 $a$ 和 $b$ 当做 $1$,另一个当做 $0$,然后就可以得到一个多项式,将这个多项式平方

BZOJ 3160 万径人踪灭 Manacher算法+快速傅里叶变换

题目大意:给定一个由'a'和'b'构成的字符串,求不连续回文子序列的个数 首先回文一定是将字符串倍增 由于求的是不连续回文子序列的个数 因此我们可以求出总回文子序列的个数,然后减掉连续的 连续的就是回文子串 用Manacher算法可以O(n)求解 不连续的就有些难搞了 首先我们令f[i]表示以i为中心的对称字符对个数 比如s[]=$#a#b#a 那么s[4]='b' f[4]=2 那么对于每个中心i我们有(2^f[i])-1种方案 答案即Σ[1<=i<=n*2+1]((2^f[i])-1) 问

BZOJ3160 万径人踪灭 字符串 多项式 Manachar FFT

原文链接http://www.cnblogs.com/zhouzhendong/p/8810140.html 题目传送门 - BZOJ3160 题意 给你一个只含$a,b$的字符串,让你选择一个子序列,使得: $1.$位置和字符都关于某一条对称轴对称. $2.$不能是连续的一段. 问原来的字符串中能找出多少个这样的子序列.答案对$10^9+7$取模. 串长$\leq 10^5$. 题解 下面的讨论都在满足条件$1$的情况下进行. 首先,我们先不考虑条件$2$.然后再减掉不满足条件$2$的就可以了

【BZOJ3160】万径人踪灭 Manacher+FFT

[BZOJ3160]万径人踪灭 Description Input Output Sample Input Sample Output HINT 题解:自己想出来1A,先撒花~(其实FFT部分挺裸的) 做这道题,第一思路很重要,显然看到这题的第一想法就是ans=总数-不合法(不要问我为什么显然).因为向这种用补集法的题一般都会给一些很奇葩的限制条件,但是一旦换个角度去想就很水了,好了不多说废话了. 显然,不合法的情况,也就是连续的回文区间的方案数,我们直接上Manacher就搞定了嘛!答案就是所

bzoj 3513: [MUTC2013]idiots -- FFT

3513: [MUTC2013]idiots Time Limit: 20 Sec  Memory Limit: 128 MB Description 给定n个长度分别为a_i的木棒,问随机选择3个木棒能够拼成三角形的概率. Input 第一行T(T<=100),表示数据组数. 接下来若干行描述T组数据,每组数据第一行是n,接下来一行有n个数表示a_i. 3≤N≤10^5,1≤a_i≤10^5 Output T行,每行一个整数,四舍五入保留7位小数. Sample Input 2 4 1 3 3

【BZOJ 2179】【FFT模板】 FFT快速傅立叶

2179: FFT快速傅立叶 Time Limit: 10 Sec Memory Limit: 259 MB Submit: 1595 Solved: 792 [Submit][Status][Discuss] Description 给出两个n位10进制整数x和y,你需要计算x*y. Input 第一行一个正整数n. 第二行描述一个位数为n的正整数x. 第三行描述一个位数为n的正整数y. Output 输出一行,即x*y的结果. Sample Input 1 3 4 Sample Output