bzoj 4598: [Sdoi2016]模式字符串 (hash+点分治)
2017-04-13 19:34
330 查看
题目描述
传送门
题目大意:给出一个n个节点的树,每个节点上有一个大写字母,给出一个模式串,求有多少路径是由模式串重复若干次得到的。题解
hash+点分治。对于每个点依次加入他的每个儿子的子树,然后计算当前儿子的子树与已经处理过的儿子的子树能形成多少合法串。
对于路径上行和下行都要考虑,用hash判断路径是否是模式串的前后缀。
注意细节。
时间复杂度应该是O(Tnlogn)
代码
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define N 1000003 #define ull unsigned long long #define p 2000001001 #define LL long long #define inf 1000000000 using namespace std; int n,m,T,n1,root,point ,nxt[N*2],v[N*2],tot,size ,f ,sz,sz1; int st ,st1 ,len ,cnt ,cnt1 ; ull mi ,a ,a1 ,b ,c ,val ,sum ,sum1 ; LL ans; bool vis ; char s ; int read() { char ch = getchar(); for ( ; ch > '9' || ch < '0'; ch = getchar()); int tmp = 0; for ( ; '0' <= ch && ch <= '9'; ch = getchar()) tmp = tmp * 10 + int(ch) - 48; return tmp; } void add(int x,int y) { tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; } void get_root(int x,int fa) { size[x]=1; f[x]=0; for (int i=point[x];i;i=nxt[i]) { if (v[i]==fa||vis[v[i]]) continue; get_root(v[i],x); f[x]=max(f[x],size[v[i]]); size[x]+=size[v[i]]; } f[x]=max(f[x],n1-size[x]); if (f[x]<f[root]) root=x; } void get_deep(int x,int fa) { if (b[len[x]]==sum[x]&&val[x]==a[1]) st[++sz]=x; for (int i=point[x];i;i=nxt[i]){ if (vis[v[i]]||v[i]==fa) continue; sum[v[i]]=sum[x]*p+val[v[i]]; len[v[i]]=len[x]+1; get_deep(v[i],x); } } void get_deep1(int x,int fa) { if (c[len[x]]==sum1[x]&&val[x]==a1[1]) st1[++sz1]=x; for (int i=point[x];i;i=nxt[i]) { if(vis[v[i]]||v[i]==fa) continue; sum1[v[i]]=sum1[x]*p+val[v[i]]; get_deep1(v[i],x); } } void calc(int x) { for (int i=0;i<=m;i++) cnt[i]=0,cnt1[i]=0; if (a[1]==val[x])cnt[1]=1; if (a[m]==val[x])cnt1[1]=1; if (m==1) ans+=cnt[1]; for (int i=point[x];i;i=nxt[i]) { if (vis[v[i]]) continue; sz=0; len[v[i]]=1; sum[v[i]]=val[v[i]]; get_deep(v[i],x); for (int j=1;j<=sz;j++) { int t=st[j]; int pos=m-(len[t]-1)%m-1; if (pos==0) pos+=m; ans+=(LL)cnt1[pos]; } sz1=0; sum1[v[i]]=val[v[i]]; get_deep1(v[i],x); for (int j=1;j<=sz1;j++) { int t=st1[j]; int pos=m-(len[t]-1)%m-1; if (pos==0) pos+=m; ans+=(LL)cnt[pos]; } for (int j=1;j<=sz;j++) { int t=st[j]; int pos=(len[t])%m+1; if (val[x]==a[pos]) cnt[pos]++; } for (int j=1;j<=sz1;j++) { int t=st1[j]; int pos=(len[t])%m+1; if (val[x]==a1[pos]) cnt1[pos]++; } } } void solve(int x) { calc(x); vis[x]=1; for (int i=point[x];i;i=nxt[i]) { if (vis[v[i]]) continue; n1=size[v[i]]; root=0; if (n1<m) continue; get_root(v[i],x); solve(root); } } int main() { freopen("a.in","r",stdin); // freopen("my.out","w",stdout); T=read(); mi[0]=1; for (int i=1;i<=1000000;i++) mi[i]=mi[i-1]*p; while (T--) { n=read(); m=read(); tot=0; ans=0; memset(point,0,sizeof(point)); scanf("%s",s+1); for (int i=1;i<=n;i++) val[i]=s[i]-'A'+1; for (int i=1;i<n;i++) { int x,y; x=read(); y=read(); add(x,y); } scanf("%s",s+1); for (int i=1;i<=max(n,m);i++) a[i]=s[(i-1)%m+1]-'A'+1; for (int i=1;i<=max(n,m);i++) b[i]=b[i-1]+a[i]*mi[i-1]; for (int i=1;i<=m;i++) a1[m-i+1]=a[i]; for (int i=1;i<=max(n,m);i++) a1[i]=a1[(i-1)%m+1]; for (int i=1;i<=max(n,m);i++) c[i]=c[i-1]+a1[i]*mi[i-1]; memset(vis,0,sizeof(vis)); f[0]=inf; root=0; n1=n; get_root(1,0); solve(root); printf("%lld\n",ans); } }
相关文章推荐
- bzoj4598 [Sdoi2016]模式字符串(hash+点分治)
- bzoj 4598: [Sdoi2016]模式字符串 点分治+hash
- [BZOJ4598][Sdoi2016]模式字符串(点分治+Hash)
- 【BZOJ4598】[Sdoi2016]模式字符串 树分治+hash
- BZOJ4598: [Sdoi2016]模式字符串
- bzoj4598 [Sdoi2016]模式字符串 hash+点分
- BZOJ 4598: [Sdoi2016]模式字符串
- bzoj 4598: [Sdoi2016]模式字符串
- [SDOI2016] 模式字符串 (BZOJ4598 & VIJOS1995)
- 4598: [Sdoi2016]模式字符串
- BZOJ4598 [Sdoi2016]模式字符串 【点分治 + hash】
- 【BZOJ 4598】【SDOI 2016 Round2 Day1 T3】模式字符串
- [BZOJ4016][FJOI2014]最短路径树问题(dijkstra+点分治)
- 【BZOJ-4435】Juice Junctions 最小割树(分治+最小割)+Hash
- BZOJ3555: [Ctsc2014]企鹅QQ(字符串hash)
- [BZOJ4317][Atm的树][LCA+点分治]
- 【bzoj3483】【SGU505】【Prefixes and suffixes】【字符串hash】
- [分治 杂题] Codeforces Gym 101173 CERC 16 G & BZOJ 4792 Geohash Grid
- 【BZOJ1014】火星人prefix Splay 字符串Hash
- BZOJ 4435 [Cerc2015]Juice Junctions 分治最小割+hash