200905-省选模拟9

省选模拟9

T2-P4323

题解

树哈希+换根dp。
异或的树哈希方式,本题不会被卡。

代码
#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define LL unsigned long long 
#define M 200009
using namespace std;
int read(){
	int f=1,re=0;char ch;
	for(ch=getchar();!isdigit(ch);ch=getchar());
	if(ch=='-'){f=-1,ch=getchar();}
	for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
	return re*f;
}
LL size[M],rta[M],f[M],rtb[M];
int n;
const LL mod=1e9+7;

tr1::unordered_map<LL,int>mp;
vector<int>a[M],b[M];
LL getrnd(LL x,LL y){return (LL)x*mod+y;}
void dfsa(int u,int fa){
	size[u]=1,f[u]=1; 
	for(int i=0;i<a[u].size();i++){
		int v=a[u][i];
		if(v==fa) continue;
		dfsa(v,u);
		f[u]^=getrnd(f[v],size[v]);
		size[u]+=size[v];
	}
}
void worka(int u,int fa){
	if(fa==0) rta[u]=f[u];
	else rta[u]=getrnd(rta[fa]^getrnd(f[u],size[u]),n-size[u])^f[u];
	for(int i=0;i<a[u].size();i++){
		int v=a[u][i];
		if(v==fa) continue;
		worka(v,u);
	}if(mp.find(rta[u])==mp.end()) mp[rta[u]]=1;
}
void dfsb(int u,int fa){
	size[u]=1,f[u]=1; 
	for(int i=0;i<b[u].size();i++){
		int v=b[u][i];
		if(v==fa) continue;
		dfsb(v,u);
		f[u]^=getrnd(f[v],size[v]);
		size[u]+=size[v];
	}
}
void workb(int u,int fa){
	if(fa==0) rtb[u]=f[u];
	else rtb[u]=getrnd(rtb[fa]^getrnd(f[u],size[u]),n+1-size[u])^f[u];
	for(int i=0;i<b[u].size();i++){
		int v=b[u][i];
		if(v==fa) continue;
		workb(v,u);
	}
}
signed main(){
	//freopen("leaf.in","r",stdin);
	//freopen("leaf.out","w",stdout);
	n=read();	
	for(int i=1;i<n;i++){
		int x=read(),y=read();
		a[x].push_back(y);
		a[y].push_back(x);
	}
	for(int i=1;i<=n;i++){
		int x=read(),y=read();
		b[x].push_back(y);
		b[y].push_back(x);
	}dfsa(1,0),worka(1,0);
	memset(f,0,sizeof(f));
	memset(size,0,sizeof(size));
	for(int i=1;i<=n+1;i++)
		if(b[i].size()>=2){
			dfsb(i,0),workb(i,0);
			break;
		}
	for(int i=1;i<=n+1;i++){
		if(b[i].size()>=2) continue;
		int ff=b[i][0];
		LL val=rtb[ff]^getrnd(f[i],1);
		if(mp.find(val)!=mp.end()){printf("%d\n",i);break;}
	}return 0;
}

T3-P4324

题解

对于1,2种情况,直接跑字符串哈希即可。
第3种情况,显然是一个串的极长回文子串延伸出去,那么在1,2种情况的基础上在二分一次即可。
时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn),细节较多。

代码
#include<bits/stdc++.h>
#define M 200009
#define LL unsigned long long
using namespace std;
int read(){
	int f=1,re=0;char ch;
	for(ch=getchar();!isdigit(ch);ch=getchar());
	if(ch=='-'){f=-1,ch=getchar();}
	for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
	return re*f;
}
int n,ans;
LL mi[M],has1[2][M],has2[2][M];
const int h=998244383;
char A[M],B[M];
LL gethas1(int x,int y,int vis){return has1[vis][y]-has1[vis][x-1]*mi[y-x+1];}
LL gethas2(int x,int y,int vis){return has2[vis][x]-has2[vis][y+1]*mi[y-x+1];}
int query1(int x,int vis){
	int l=1,r=min(x,n-x),maxn,len,rr=0,x1,x2;
	while(l<=r){//本身串的回文串 
		int mid=(l+r)>>1;
		if(gethas1(x-mid,x+mid,vis)==gethas2(x-mid,x+mid,vis)) l=mid+1;
		else r=mid-1;
	}len=r;
	if(vis){
		x1=x+len+1,x2=x-len;
		l=1,r=min(x2,n-x1+1);
		while(l<=r){//左短右长 
			int mid=(l+r)>>1;
			if(gethas1(x1,x1+mid,vis)==gethas2(x2-mid,x2,vis^1)) l=mid+1,rr=l;
			else r=mid-1;	
		}maxn=len+rr;
	}
	else{
		x1=x+len,x2=x-len-1;
		l=1,r=min(x2,n-x1+1);
		while(l<=r){//左长右短 
			int mid=(l+r)>>1;
			if(gethas1(x1,x1+mid,vis^1)==gethas2(x2-mid,x2,vis)) l=mid+1,rr=l;
			else r=mid-1;	
		}maxn=len+rr;
	}return maxn;
}
int query2(int x,int vis){
	int l=1,r=min(x,n-x),maxn,len,rr=0,x1,x2;
	while(l<=r){
		int mid=(l+r)>>1;
		if(gethas2(x-mid+1,x+mid,vis)==gethas1(x-mid+1,x+mid,vis)) l=mid+1;
		else r=mid-1;
	}len=r;
	if(vis){
		int x1=x+len+1,x2=x-len+1;
		l=1,r=min(x2,n-x1+1);
		while(l<=r){//左短右长 
			int mid=(l+r)>>1;
			if(gethas1(x1,x1+mid,vis)==gethas2(x2-mid,x2,vis^1)) l=mid+1,rr=l;
			else r=mid-1;	
		}maxn=len+rr;
	}
	else{
		x1=x+len,x2=x-len;
		l=1,r=min(x2,n-x1+1);
		while(l<=r){//左长右短 
			int mid=(l+r)>>1;
			if(gethas1(x1,x1+mid,vis^1)==gethas2(x2-mid,x2,vis)) l=mid+1,rr=l;
			else r=mid-1;	
		}maxn=len+rr;
	}return maxn;
}
void getans(int vis){
	for(int i=1;i<=n;i++){
		int a=query1(i,vis)*2+1;
		int b=query2(i,vis)*2;
		//cout<<a<<" "<<b<<endl;
		//if(a>100||b>100) cout<<vis<<" "<<i<<" "<<a<<" "<<b<<endl;
		//if(a==19) cout<<i<<endl;
		ans=max(ans,max(a,b));
	}
}
signed main(){
	//freopen("palindrome.in","r",stdin);
	//freopen("palindrome.out","w",stdout);
	n=read();mi[0]=1;
	scanf("%s",A+1);
	scanf("%s",B+1);
	for(int i=1;i<=n;i++) mi[i]=mi[i-1]*h;
	for(int i=1;i<=n;i++) has1[0][i]=has1[0][i-1]*h+(A[i]-'A'+1);
	for(int i=n;i>=1;i--) has2[0][i]=has2[0][i+1]*h+(A[i]-'A'+1);
	for(int i=1;i<=n;i++) has1[1][i]=has1[1][i-1]*h+(B[i]-'A'+1);
	for(int i=n;i>=1;i--) has2[1][i]=has2[1][i+1]*h+(B[i]-'A'+1);
	getans(0);
	getans(1);
	printf("%d\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值