[SDOI2016]模式字符串
阿新 • • 發佈:2019-05-03
for tps tchar signed while tin lld 分治 是否
題目
bzoj第400題留念
這道題如果只有前三組數據的話還是很水的呀,我們完全可以點分
首先我們先倍長那個字符串,直到這個字符串的長度大於等於\(n\)
我們把這個字符串做一遍\(hash\),記下每一個前綴每一個後綴的\(hash\)值是多少
之後套路點分,對於當前的分治重心找出一個前綴一個後綴來拼接,由於我們倍長了原串,我們可以方便的直到當前連通塊裏某個點到分治重心的路徑是否能形成一個前綴或一個後綴,我們開一個桶記錄一下就好了
之後就只有\(bxoj\)上能過了
代碼
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define re register #define LL long long #define max(a,b) ((a)>(b)?(a):(b)) #define ull unsigned int #pragma GCC optimize(3) inline int read() { char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x; } const int maxn=1e5+5; const int inf=999999999; struct E{int v,nxt;}e[maxn<<1]; int head[maxn],vis[maxn],sum[maxn],mx[maxn],st[maxn],tax[maxn],cl[maxn]; int n,num,Case,rt,Ss,top,tot,m,len;LL ans=0; ull ha[maxn],pw[maxn],base=233,pr[maxn],bh[maxn]; char S[maxn],a[maxn],T[maxn]; inline void add(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;} void getroot(int x,int fa) { sum[x]=1;mx[x]=0; for(re int i=head[x];i;i=e[i].nxt) { if(vis[e[i].v]||e[i].v==fa) continue; getroot(e[i].v,x);sum[x]+=sum[e[i].v]; mx[x]=max(mx[x],sum[e[i].v]); } mx[x]=max(mx[x],Ss-sum[x]); if(mx[x]<mx[rt]) rt=x; } void getpre(int x,int l,ull sh,int fa) { sh=sh+a[x]*pw[l]; if(pr[l+1]==sh) st[++top]=(l+1)%m; for(re int i=head[x];i;i=e[i].nxt) { if(vis[e[i].v]||e[i].v==fa) continue; getpre(e[i].v,l+1,sh,x); } } void getbeh(int x,int l,ull sh,int fa) { sh=sh*base+a[x]; if(bh[l]==sh) ans+=tax[(m-l%m)%m]; for(re int i=head[x];i;i=e[i].nxt) { if(vis[e[i].v]||e[i].v==fa) continue; getbeh(e[i].v,l+1,sh,x); } } void dfs(int x) { vis[x]=1;tot=0; if(a[x]==S[1]) tax[1]++; for(re int i=head[x];i;i=e[i].nxt) { if(vis[e[i].v]) continue; getbeh(e[i].v,1,0,x); top=0;getpre(e[i].v,1,a[x],x); while(top) tax[st[top]]++,cl[++tot]=st[top--]; } tax[1]=0; while(tot) tax[cl[tot--]]=0; for(re int i=head[x];i;i=e[i].nxt) { if(vis[e[i].v]) continue; Ss=sum[e[i].v];rt=0;getroot(e[i].v,0);dfs(rt); } } inline void work() { for(re int i=1;i<=len;i++) ha[i]=ha[i-1]*base+S[(i%m)?i%m:m]; for(re int i=1;i<=len;i++) pr[i]=ha[i]; for(re int i=1;i<=len;i++) bh[i]=ha[len]-ha[len-i]*pw[i]; Ss=n,rt=0,getroot(1,0),dfs(rt); } int main() { Case=read();mx[0]=inf; pw[0]=1;for(re int i=1;i<(maxn<<1);i++) pw[i]=pw[i-1]*base; while(Case--) { memset(vis,0,sizeof(vis));memset(head,0,sizeof(head)); n=read(),m=read();num=0;scanf("%s",a+1); for(re int x,y,i=1;i<n;i++) x=read(),y=read(),add(y,x),add(x,y); scanf("%s",S+1);len=m; while(len<n) len+=m; ans=0;work(); for(re int i=1;i<=m;i++) T[i]=S[i]; for(re int i=1;i<=m;i++) S[i]=T[m-i+1]; for(re int i=1;i<=n;i++) vis[i]=0; work();printf("%lld\n",ans); } return 0; }
[SDOI2016]模式字符串