zoukankan      html  css  js  c++  java
  • 【BZOJ4166】月宫的符卡序列 Manacher+hash

    【BZOJ4166】月宫的符卡序列

    题解:题倒不难,就是有点恶心。

    首先学习回文串的时候一定学到了这样一个结论:一个长度为n的串的本质不同的回文子串数量不超过n个。

    那么我们就可以试图将所有回文串的价值都计算出来,这就需要我们先计算出每个回文中心i的最长回文半径rl[i],那么那些半径在[1,rl[i]]中的,且以i为回文中心的回文串的价值都应该被更新。其实只需要更新最长的那个就行,其余的可以扫一遍回文树,逐层更新上去。但是回文树太大建不出来怎么办?我们可以用hash,直接通过hash值得到每个串在回文树上的父亲。这样就可以更新了。

    但是hash要用到map啊,然后本人就被光荣的卡常了。于是采取了一点黑科技~

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <vector>
    using namespace std;
    typedef long long ll;
    const int maxn=2000010;
    vector<int> v[maxn];
    const ll m1=9997957;
    const ll m2=1000000007;
    int n,tot,len,ml,pos,mx;
    char str[maxn],ss[maxn];
    int rl[maxn],ans[maxn],p[maxn];
    int head[10000000],next[maxn];
    ll h1[maxn],b1[maxn],h2[maxn],b2[maxn],val[maxn];
    int find(ll t1,ll t2)
    {
    	for(int i=head[t1];i;i=next[i])	if(val[i]==t2)	return i;
    	return 0;
    }
    void add(ll t1,ll t2)
    {
    	val[++tot]=t2,next[tot]=head[t1],head[t1]=tot;
    }
    void work()
    {
    	n=tot=mx=0;
    	memset(ans,0,sizeof(ans));
    	memset(rl,0,sizeof(rl));
    	memset(head,0,sizeof(head));
    	scanf("%s",ss),len=strlen(ss);
    	int i,j,k,t;
    	ll t1,t2;
    	str[n++]='*';
    	for(i=0;i<len;i++)	str[n++]=ss[i],str[n++]='*';
    	for(ml=-1,i=0;i<n;i++)
    	{
    		if(i<ml)	rl[i]=min(ml-i+1,rl[2*pos-i]);
    		else	rl[i]=1;
    		for(;rl[i]<=i&&i+rl[i]<n&&str[i+rl[i]]==str[i-rl[i]];rl[i]++);
    		if(i+rl[i]-1>ml)	pos=i,ml=i+rl[i]-1;
    	}
    	for(b1[0]=b2[0]=1,i=1;i<=n;i++)	b1[i]=b1[i-1]*233%m1,b2[i]=b2[i-1]*2333%m2;
    	for(i=0;i<n;i++)
    	{
    		if(i)	h1[i]=h1[i-1]*233%m1,h2[i]=h2[i-1]*2333%m2;
    		h1[i]=(h1[i]+str[i])%m1,h2[i]=(h2[i]+str[i])%m2;
    	}
    	for(i=0;i<n;i++)
    	{
    		if(rl[i]==1)	continue;
    		t1=(h1[i+rl[i]-1]-h1[i-1]*b1[rl[i]]%m1+m1)%m1;
    		t2=(h2[i+rl[i]-1]-h2[i-1]*b2[rl[i]]%m2+m2)%m2;
    		t=find(t1,t2);
    		if(t)
    		{
    			ans[t]^=(i-1>>1);
    			continue;
    		}
    		add(t1,t2),ans[tot]=(i-1>>1),p[tot]=i,v[rl[i]-1].push_back(tot);
    	}
    	for(i=len;i;i--)
    	{
    		for(j=0;j<v[i].size();j++)
    		{
    			k=v[i][j],mx=max(mx,ans[k]);
    			if(i==1)	continue;
    			t1=(h1[p[k]+i-1]-h1[p[k]-1]*b1[i]%m1+m1)%m1;
    			t2=(h2[p[k]+i-1]-h2[p[k]-1]*b2[i]%m2+m2)%m2;
    			t=find(t1,t2);
    			if(t)
    			{
    				ans[t]^=ans[k];
    				continue;
    			}
    			add(t1,t2),ans[tot]=ans[k],p[tot]=p[k],v[i-1].push_back(tot);
    		}
    		v[i].clear();
    	}
    	printf("%d
    ",mx);
    }
    int main()
    {
    	int T;
    	scanf("%d",&T);
    	while(T--)	work();
    	return 0;
    }
  • 相关阅读:
    win32: 静态控件(Static)
    malloc() 和 calloc()有啥区别
    win32: WM_PAINT 实现双缓冲缓图
    char 与 unsigned char的本质区别
    iconv: iconv_open(pToCharset, pFromCharset); 的附加参数//IGNORE
    c语言: 生成随机数
    深圳市住房公积金管理中心
    利用latex制作个人简历
    分布式系统概念与设计中文版(第三版)
    数据结构-红黑树
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7114744.html
Copyright © 2011-2022 走看看