zoukankan      html  css  js  c++  java
  • [BZOJ3160]万径人踪灭

    bzoj
    luogu

    题意

    就是要在一个只含(a,b)的字符串中选取一个子序列,使得:
    1、位置和字符都关于某条对称轴对称。
    2、不能是连续的一段。
    求方案数模(10^9+7,nle10^5)

    sol

    其实就是对于任意一个对称中心,你算出关于它对称的有多少位置,假设是(f_i)那么一个对称中心的贡献就是(2^{f_i}-1)(从中选取一个非空子集即可)。
    但是这可能是连续的呀!
    你想想连续的会是什么。回文串?
    那么连续的个数其实就是字符串中回文串的个数!

    到这里思路就比较清晰了,我们只需要求出“对于任意一个对称中心,有多少位置关于它对称”。
    想一想两个字符关于某一个位置对称的形式化表示?
    (s[i]==s[2x-i])
    其中(x)就是对称中心的位置,注意因为对称中心可以使某个夹缝,所以(x)是可以取(k+0.5(kin Z))的。
    上面那个东西像什么?会发现两个下标之和(i+(2x-i)=2x)是一个常数,卷积?
    对于每种字符(ch),设多项式(f(x))其中(f(i)=[s[i]==ch]),我们只要对这个多项式卷积一下就可以求出每个位置有多少对满足对称关系的字符了。
    因为在卷积中每对不同位置的对称字符被计算了两次,而相同位置的对称字符(自己和自己关于自身对称)只计算了一次,所以要把答案除2向上取整。

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    const double Pi = acos(-1);
    const int mod = 1e9+7;
    const int N = 4e5+5;
    struct Complex{
    	double rl,im;
    	Complex(){rl=im=0;}
    	Complex(double a,double b){rl=a;im=b;}
    	Complex operator + (Complex b)
    		{return Complex(rl+b.rl,im+b.im);}
    	Complex operator - (Complex b)
    		{return Complex(rl-b.rl,im-b.im);}
    	Complex operator * (Complex b)
    		{return Complex(rl*b.rl-im*b.im,rl*b.im+im*b.rl);}
    }w[N],a[N];
    int n,m,l,rev[N],tw[N],f[N],p[N],mx,id,ans;
    char s[N];
    void FFT(Complex *P,int opt)
    {
    	for (int i=0;i<n;++i) if (i>rev[i]) swap(P[i],P[rev[i]]);
    	for (int i=1;i<n;i<<=1)
    		for (int p=i<<1,j=0;j<n;j+=p)
    			for (int k=0;k<i;++k)
    			{
    				Complex W=w[n/i*k];W.im*=opt;
    				Complex X=P[j+k],Y=W*P[j+k+i];
    				P[j+k]=X+Y;P[j+k+i]=X-Y;
    			}
    	if (opt==-1) for (int i=0;i<n;++i) P[i].rl/=1.0*n;
    }
    void work(char ch)
    {
    	for (int i=0;i<n;++i) a[i]=Complex(s[i]==ch,0);
    	FFT(a,1);
    	for (int i=0;i<n;++i) a[i]=a[i]*a[i];
    	FFT(a,-1);
    	for (int i=2;i<=(m<<1);++i) f[i]+=((int)(a[i].rl+0.5)+1)/2;
    }
    int main()
    {
    	scanf("%s",s+1);m=strlen(s+1);
    	tw[0]=1;
    	for (int i=1;i<=m;++i) tw[i]=2ll*tw[i-1]%mod;
    	for (n=1;n<=(m<<1);n<<=1) ++l;--l;
    	for (int i=0;i<n;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<l);
    	for (int i=0;i<n;++i) w[i]=Complex(cos(Pi*i/n),sin(Pi*i/n));
    	work('a');work('b');
    	for (int i=2;i<=(m<<1);++i)
    		(ans+=tw[f[i]]-1)%=mod;
    	s[0]='%';s[m<<1|1]='#';
    	for (int i=m;i;--i)
    		s[2*i]=s[i],s[2*i-1]='#';
    	for (int i=1;i<=(m<<1);++i)
    	{
    		p[i]=mx>i?min(p[2*id-i],mx-i):1;
    		while (s[i-p[i]]==s[i+p[i]]) ++p[i];
    		if (i+p[i]>mx) mx=i+p[i],id=i;
    	}
    	for (int i=1;i<=(m<<1);++i)
    		ans=(ans-p[i]/2+mod)%mod;
    	printf("%d
    ",ans);return 0;
    }
    
  • 相关阅读:
    'Undefined symbols for architecture i386,clang: error: linker command failed with exit code 1
    The codesign tool requires there only be one 解决办法
    XCode iOS project only shows “My Mac 64bit” but not simulator or device
    Provisioning profile XXXX can't be found 的解决办法
    UIView 中的控件事件穿透 Passthrough 的实现
    Xcode4.5出现时的OC新语法
    xcode 快捷键(持续更新)
    打越狱包
    php缓存与加速分析与汇总
    浏览器的判断
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8672807.html
Copyright © 2011-2022 走看看