[2019寒假集训day1]三元组(Manacher+差分)

题面

[2019寒假集训day1]三元组(Manacher+差分)_第1张图片

题解

被题解坑到自闭系列…
不得不说能把一道这么简单的题写的如此好理解也是一种能力

明显首先需要Manacher,然后得到最大半径pip_ipi,发现对答案的贡献是一个等差序列。
于是我们可以用6个数组维护等差序列。
分别是ls1i,ls2i,ls3i,rs1i,rs2i,rs3ils1_i,ls2_i,ls3_i,rs1_i,rs2_i,rs3_ils1i,ls2i,ls3i,rs1i,rs2i,rs3i
分别代标从iii点开始的首项之和,公差之和,与公差之和的和
以及从iii点结束的首项之和,公差之和,与公差之和的和
这里指的公差之和的和就是首先为1得等差序列,统计答案时加上首项之和即可。
按照如下规则差分

int l=(i-p[i])/2,r=(i+p[i]-1)/2,mid=(i-1)/2;
ls1[l]+=(r+1),ls1[mid+1]-=(r+1);
ls2[l+1]--,ls2[mid+1]++;
ls3[mid+1]+=(mid-l);
mid=i/2;
rs1[mid]+=(i+1)/2,rs1[r+1]-=(i+1)/2;
rs2[mid+1]--,rs2[r+1]++;
rs3[r+1]+=(r-mid);

然后答案就是(ls1[i]+ls3[i])∗(rs1[i−1]+rs3[i−1])(ls1[i]+ls3[i])*(rs1[i-1]+rs3[i-1])(ls1[i]+ls3[i])(rs1[i1]+rs3[i1])
细节超多…
复杂度:O(n)O(n)O(n)

#include
#include
#include
#include
using namespace std;
#define MAXN 1000000
#define LL long long
#define MOD 1000000007
int T,len,n;
char LS[MAXN*2+5],s[MAXN*2+5];
int p[MAXN*2+5];
LL ls1[MAXN+5],ls2[MAXN+5],ls3[MAXN+5],rs1[MAXN+5],rs2[MAXN+5],rs3[MAXN+5],ans;
void Init()
{
    s[0]='#';
    for(int i=2;i<=len*2;i+=2)
    {
        s[i-1]=LS[i/2];
        s[i]='#';
    }
    s[len*2]='#';
}
void prefix_s(LL *s1,LL* s2,LL *s3,int p)
{
	s1[p]+=s1[p-1];s1[p]%=MOD;
	s2[p]+=s2[p-1];s2[p]%=MOD;
	s3[p]+=s3[p-1]+s2[p];s3[p]%=MOD;
}
void Manacher()
{
    Init();
    len=strlen(s);
    int pos,mr=0;
    for(int i=1;i<len;i++)
    {
        if(i<mr)p[i]=min(p[pos*2-i],mr-i);
        else p[i]=0;
        while(i+p[i]+1<=len&&i-p[i]-1>=0&&s[i-p[i]-1]==s[i+p[i]+1])p[i]++;
        if(mr<p[i]+i)mr=p[i]+i,pos=i;
        if(p[i]!=0)
        {
        	int l=(i-p[i])/2,r=(i+p[i]-1)/2,mid=(i-1)/2;
        	ls1[l]+=(r+1),ls1[mid+1]-=(r+1);
			ls2[l+1]--,ls2[mid+1]++;
			ls3[mid+1]+=(mid-l);
			mid=i/2;
			rs1[mid]+=(i+1)/2,rs1[r+1]-=(i+1)/2;
			rs2[mid+1]--,rs2[r+1]++;
			rs3[r+1]+=(r-mid);
        }
    }
    return ;
}
int main()
{
	freopen("triple.in","r",stdin);
	freopen("triple.out","w",stdout);
	scanf("%d",&T);
    while(T--)
    {
		scanf("%s",LS+1);
        len=n=strlen(LS+1);
        memset(s,0,sizeof(s));
        for(int i=0;i<=n+1;i++)
        ls1[i]=ls2[i]=ls3[i]=rs1[i]=rs2[i]=rs3[i]=0;
        p[0]=0;ans=0;
		Manacher();
    	for(int i=1;i<=n;i++)
    	{
    		prefix_s(ls1,ls2,ls3,i);
    		prefix_s(rs1,rs2,rs3,i);
    		ans=(ans+((ls1[i]+ls3[i])%MOD)*((rs1[i-1]+rs3[i-1])%MOD)%MOD)%MOD;
    	}
        printf("%lld\n",ans);
    }
}

转载于:https://www.cnblogs.com/Panda-hu/p/11145739.html

你可能感兴趣的:([2019寒假集训day1]三元组(Manacher+差分))