省选模拟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;
}