[SDOI2016] 模式字符串 (BZOJ4598 & VIJOS1995)
2017-03-02 13:15
239 查看
首先直接点分+hash就可以做,每个点用hash判断是否为S重复若干次后的前缀或后缀,每个子树与之前的结果O(m)暴力合并。在子树大小<m时停止分治,则总复杂度为O(nlog(n/m))。
问题在于n<=1e6。据说有O(n)的DP做法?写点分的话需要一大波常数优化……据说SDOI现场写了这题的全卡常T了……注意BZOJ并没有大数据,如果常数够小的话可以去VIJOS提交。
#include<bits/stdc++.h> using namespace std; typedef unsigned long long u64; typedef u64 ll; const int N=1e6+5; struct edge{int v;edge*s;}e[N*2]; edge*l1=e,*h ; void ins(int u,int v){ edge s={v,h[u]}; *(h[u]=l1++)=s; } int q,n,m,s1,s2,s3,d=1,siz ,f1 ,f2 ,f3 ,f4 ; bool vis ; char t1 ,t2 ; ll c1 ,c2 ; u64 ans; void dfs1(int u,int v){ int s4=0; s3=max(s3,d++); siz[u]=1; for(edge*i=h[u];i;i=i->s) if(i->v!=v&&!vis[i->v]){ dfs1(i->v,u); siz[u]+=siz[i->v]; s4=max(s4,siz[i->v]); } if(max(s4,s1-siz[u])*2<=s1) s2=u; --d; } void dfs3(int u,int v,ll w){ ++d,w=w*223+t1[u]; if(w==c1[d])++f1[d%m]; if(w==c2[d])++f2[d%m]; for(edge*i=h[u];i;i=i->s) if(i->v!=v&&!vis[i->v]) dfs3(i->v,u,w); --d; } void dfs2(int u){ s3=0,dfs1(u,0),u=s2; if(s3*2-1<m)return; for(int j=0;j<m;++j) f3[j]=f4[j]=0; f3[1]=f4[1]=1; for(edge*i=h[u];i;i=i->s) if(!vis[i->v]){ for(int j=0;j<m;++j) f1[j]=f2[j]=0; dfs3(i->v,u,t1[u]); for(int j=0;j<m;++j) ans+=(u64)f1[j]*f4[(m-j+1)%m]+(u64)f2[j]*f3[(m-j+1)%m]; for(int j=0;j<m;++j) f3[j]+=f1[j],f4[j]+=f2[j]; } vis[u]=1; int s5=s1; for(edge*i=h[u];i;i=i->s) if(!vis[i->v]){ s1=siz[i->v]<siz[u]?siz[i->v]:s5-siz[u]; if(s1>=m)dfs2(i->v); } } struct buf{ char z[1<<25],*s; buf():s(z){ z[fread(z,1,sizeof z,stdin)]=0; } void pre(char*v){ while(*s<48)++s; while(*s>32)*v++=*s++; *v=0; } operator int(){ int x=0; while(*s<48)++s; while(*s>32) x=x*10+*s++-48; return x; } }it; int main(){ q=it; while(q--){ n=it,m=it,it.pre(t1+1); for(int i=1;i<=n;++i) h[i]=0,vis[i]=0; l1=e; for(int i=2;i<=n;++i){ int u=it,v=it; ins(u,v),ins(v,u); } it.pre(t2+1); ll w=1; int i=1; int j=m; for(int k=1;k<=n;++k){ c1[k]=c1[k-1]+w*t2[i]; c2[k]=c2[k-1]+w*t2[j]; w*=223; if(++i>m)i=1; if(--j<1)j=m; } ans=0,s1=n,dfs2(1); printf("%llu\n",ans); } }
相关文章推荐
- bzoj 4598: [Sdoi2016]模式字符串 (hash+点分治)
- BZOJ 4598: [Sdoi2016]模式字符串
- BZOJ4598: [Sdoi2016]模式字符串
- bzoj 4598: [Sdoi2016]模式字符串 点分治+hash
- bzoj 4598: [Sdoi2016]模式字符串
- bzoj4598 [Sdoi2016]模式字符串(hash+点分治)
- bzoj4598 [Sdoi2016]模式字符串 hash+点分
- 4598: [Sdoi2016]模式字符串
- 【BZOJ4598】[Sdoi2016]模式字符串 树分治+hash
- 【BZOJ 4598】【SDOI 2016 Round2 Day1 T3】模式字符串
- [BZOJ4598][Sdoi2016]模式字符串(点分治+Hash)
- vijos 1057 盖房子 悬线法 && BZOJ 1057 棋盘制作
- (字符串的模式匹配4.7.8)UVA 10008 What's Cryptanalysis?(统计文本中某一个字符的出现的次数,需要从小到大排序&&同次数的按字段序排序)
- bzoj4598: [Sdoi2016]模式字符串
- BZOJ 1398: Vijos1382寻找主人 Necklace 字符串最小表示法
- bzoj3473: 字符串 && bzoj3277串
- bzoj1067 降雨量&&vijos1265 暴风雨
- [NOIP2014] 解方程&加强版 (BZOJ3751 & VIJOS1915)
- 【TJOI&HEOI2016】bzoj4556 字符串【解法一】
- BZOJ 1398: Vijos1382寻找主人 Necklace【字符串最小表示