• [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;
    }
    
  • 相关阅读:
    设置MySQL的字符编码
    数据库面试题
    java.lang.IncompatibleClassChangeError: Implementing class
    下载SpringJar包
    使用命令wsimport构建WebService客户端
    java读取.properties配置文件的几种方法
    ELK5.X使用X-Pack配置密码
    Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'
    MySQL常用命令
    XPath常用定位节点元素语句总结
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8672807.html
Copyright © 2020-2023  润新知