Palindromic Problem

主要是复习二分+哈希的思想,考虑贡献的思想也比较自然,题目也不是很难

然后想一下怎么 用差分维护一次项系数和常数项系数,具体下面的代码

#include<bits/stdc++.h>
#define ll long long
#define ULL unsigned long long
using namespace std;
const ULL mod=1721;
const int N=3e5+5;
ULL power[N];
char s[N];
ULL Hash1[N],Hash2[N];
int l;
ll cnt[N][30],sum[3][N][3],d[3][N][3];
ll Sum;
int main()
{
	power[0]=1;
	for(int i=1;i<=N-5;i++)
	power[i]=power[i-1]*mod;
	scanf("%d",&l);
	scanf("%s",s);
	Hash1[0]=Hash2[l+1]=0;//hash1是前缀哈希,hash2是后缀哈希 
	for(int i=0;i<l;i++) 
	Hash1[i+1]=Hash1[i]*mod+(ULL)(s[i]-'a'+1);
	for(int i=l-1;i>=0;i--)
	Hash2[i+1]=Hash2[i+2]*mod+(ULL)(s[i]-'a'+1);
	for(int i=1;i<=l;i++)
	{
		//这一部分以某一字符为中心 
	    int L=0,r=min(i-1,l-i),mid,x,y=0;
	    while(L<=r)
	    {
	    	mid=L+r>>1;
	    	if(Hash1[i-1]-Hash1[i-mid-1]*power[mid]==Hash2[i+1]-Hash2[i+mid+1]*power[mid])
	    	{
	    		x=mid;
	    		L=mid+1;
	    	}
		    else r=mid-1;
		}
		Sum+=x+1;
		L=0,r=min(i-x-2,l-i-x-1);
		while(L<=r)
		{
			mid=L+r>>1;
			if(Hash1[i-x-2]-Hash1[i-x-mid-2]*power[mid]==Hash2[i+x+2]-Hash2[i+x+mid+2]*power[mid])
	    	{
	    		y=mid;
	    		L=mid+1;
	    	}
		    else r=mid-1;
		}
		//cnt[i][j]是将第i个字符修改为j的增量 
		if(i+x<l&&i-x-2>=0)
		{
		    cnt[i-x-1][s[i+x]-'a']+=y+1;
		    cnt[i+x+1][s[i-x-2]-'a']+=y+1;
		}
		//d[0/1][i][0/1]表示的是如果修改第i个字符的减少量
		//第一维表示是前缀差分还是后缀差分
		//第三维表示是常数项系数还是一次项系数 
		d[0][i-x][1]++,d[0][i][1]--;
		d[0][i-x][0]+=x+1-i,d[0][i][0]-=x+1-i;
		d[1][i+x][1]--,d[1][i][1]++;
		d[1][i+x][0]+=x+1+i,d[1][i][0]-=x+1+i;
		if(i==1) continue;
		//这一部分是以两个字符的中间为中心 
		L=0,r=min(i-1,l-i+1),x=0;
		while(L<=r)
		{
			mid=L+r>>1;
			if(Hash1[i-1]-Hash1[i-mid-1]*power[mid]==Hash2[i]-Hash2[i+mid]*power[mid])
			{
				x=mid;
				L=mid+1;
			}
			else r=mid-1;
		}
		Sum+=x;
		L=0,r=min(i-x-2,l-i-x),y=0;
		while(L<=r)
		{
			mid=L+r>>1;
			if(Hash1[i-x-2]-Hash1[i-x-mid-2]*power[mid]==Hash2[i+x+1]-Hash2[i+x+mid+1]*power[mid])
	    	{
	    		y=mid;
	    		L=mid+1;
	    	}
		    else r=mid-1;
		}
		if(i+x-1<l&&i-x-2>=0)
		{
		    cnt[i-x-1][s[i+x-1]-'a']+=y+1;
		    cnt[i+x][s[i-x-2]-'a']+=y+1;
		}
		d[0][i-x][1]++,d[0][i][1]--;
		d[0][i-x][0]+=x+1-i,d[0][i][0]-=x+1-i;
		d[1][i+x-1][1]--,d[1][i-1][1]++;
		d[1][i+x-1][0]+=x+i,d[1][i-1][0]-=x+i;
	}
	for(int i=1;i<=l;i++) 
	for(int j=0;j<=1;j++)
	sum[0][i][j]=sum[0][i-1][j]+d[0][i][j];
	for(int i=l;i>=1;i--) 
	for(int j=0;j<=1;j++)
	sum[1][i][j]=sum[1][i+1][j]+d[1][i][j];
	for(int i=1;i<=l;i++)
	cnt[i][26]=(sum[0][i][1]+sum[1][i][1])*i+sum[0][i][0]+sum[1][i][0];
	ll Max=-1;
	for(int i=1;i<=l;i++)
	for(int j=0;j<26;j++)
	Max=max(Max,cnt[i][j]-cnt[i][26]);
	if(Max<0)
	{
		printf("%lld\n",Sum);
		printf("%s",s);
		return 0;
	}
	else if(!Max)
	{
		printf("%lld\n",Sum);
		for(int i=1;i<=l;i++)
		for(int j=0;j<26;j++)
		if(cnt[i][j]-cnt[i][26]==Max)
		{
			if(s[i-1]>j+'a')
			{
				for(int k=0;k<i-1;k++)
				printf("%c",s[k]);
				printf("%c",j+'a');
				for(int k=i;k<l;k++)
				printf("%c",s[k]);
				return 0;
			}
		}
		printf("%s",s);
		return 0;
	}
	int last;
	for(int i=1;i<=l;i++)
	for(int j=0;j<26;j++)
	if(cnt[i][j]-cnt[i][26]==Max) last=i;
	for(int i=1;i<=l;i++)
	for(int j=0;j<26;j++)
	if(cnt[i][j]-cnt[i][26]==Max)
	{
		if(s[i-1]>j+'a'||i==last)
		{
			printf("%lld\n",Sum+Max);
			for(int k=0;k<i-1;k++)
			printf("%c",s[k]);
			printf("%c",j+'a');
			for(int k=i;k<l;k++)
			printf("%c",s[k]);
			return 0;
		}
	}
	return 0;
}
posted @ 2024-07-11 13:59  最爱丁珰  阅读(1)  评论(0编辑  收藏  举报