bzoj 4598: [Sdoi2016]模式字符串
2018-08-17 12:54
363 查看
题目描述
给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m的模式串s,其中每一位仍然是A到z的大写字母。Alice希望知道,有多少对结点<u,v>满足T上从u到V的最短路径形成的字符串可以由模式串S重复若干次得到?
这里结点对<u,v>是有序的,也就是说<u,v>和<v,u>需要被区分。
所谓模式串的重复,是将若干个模式串S依次相接(不能重叠)。例如当S=
PLUS的时候,重复两次会得到
PLUSPLUS,重复三次会得到
PLUSPLUSPLUS,同时要注恿,重复必须是整数次的。例如当S=
XYXY时,因为必须重复整数次,所以
XYXYXY不能看作是S重复若干次得到的。
输入输出格式
输入格式:每一个数据有多组测试,
第一行输入一个整数C,表示总的测试个数。
对于每一组测试来说:
第一行输入两个整数,分别表示树T的结点个数n与模式长度m。结点被依次编号为1到n,
之后一行,依次给出了n个大写字母(以一个长度为n的字符串的形式给出),依次对应树上每一个结点上的字符(第i个字符对应了第i个结点)。
之后n-1行,每行有两个整数u和v表示树上的一条无向边,之后一行给定一个长度为m的由大写字母组成的字符串,为模式串S。
输出格式:
给出C行,对应C组测试。
每一行输出一个整数,表示有多少对节点<u,v>满足从u到v的路径形成的字符串恰好是模式串的若干次重复.
输入输出样例
输入样例#1: 复制1 11 4 IODSSDSOIOI 1 2 2 3 3 4 1 5 5 6 6 7 3 8 8 9 6 10 10 11 SDOI
输出样例#1: 复制
5
说明
1<=C<=10,3<=N<=1000000,3<=M<=1000000[b]题解[/b]
题解大概看懂一点了……就是说用hash+点分治……好讨厌hash……总感觉还是半懂不懂……
考虑每一个分治点,从他延伸下去能形成长度为多少的前缀和后缀(不包含自己和包含自己),然后两个两两组合起来计算答案
据说时间复杂度$O(Tnlogn)$,数据就是为了卡点分的,然而因为全世界都只有前三组数据……所以能A……
//minamoto #include<cstdio> #include<iostream> #include<cstring> #define N 1000003 #define ull unsigned long long #define ll long long #define p 2000001001 #define inf 1000000000 using namespace std; template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} inline int read(){ #define num ch-'0' char ch;bool flag=0;int res; while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true); for(res=num;isdigit(ch=getchar());res=res*10+num); (flag)&&(res=-res); #undef num return res; } char sr[1<<21],z[30];int C=-1,Z; inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} inline void print(ll x){ if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; while(z[++Z]=x%10+48,x/=10); while(sr[++C]=z[Z],--Z);sr[++C]='\n'; } int n,m,T,n1,rt,head ,Next[N<<1],ver[N<<1],tot,size ,son ,sz,sz1; int st ,st1 ,len ,cnt ,cnt1 ; ull mi ,a ,a1 ,b ,c ,val ,sum ,sum1 ; ll ans; bool vis ;char s ; inline void add(int u,int v){ ver[++tot]=v,Next[tot]=head[u],head[u]=tot; ver[++tot]=u,Next[tot]=head[v],head[v]=tot; } void findrt(int u,int fa){ size[u]=1,son[u]=0; for(int i=head[u];i;i=Next[i]){ int v=ver[i]; if(vis[v]||v==fa) continue; findrt(v,u); cmax(son[u],size[v]); size[u]+=size[v]; } cmax(son[u],n1-size[u]); if(son[u]<son[rt]) rt=u; } void getdep(int u,int fa){ if(b[len[u]]==sum[u]&&val[u]==a[1]) st[++sz]=u; for(int i=head[u];i;i=Next[i]){ int v=ver[i];if(vis[v]||v==fa) continue; sum[v]=sum[u]*p+val[v]; len[v]=len[u]+1; getdep(v,u); } } void getdep1(int u,int fa){ if(c[len[u]]==sum1[u]&&val[u]==a1[1]) st1[++sz1]=u; for(int i=head[u];i;i=Next[i]){ int v=ver[i]; if(vis[v]||v==fa) continue; sum1[v]=sum1[u]*p+val[v]; getdep1(v,u); } } void calc(int u){ for(int i=0;i<=m;++i) cnt[i]=cnt1[i]=0; if(a[1]==val[u]) cnt[1]=1; if(a[m]==val[u]) cnt1[1]=1; if(m==1) ans+=cnt1[1]; for(int i=head[u];i;i=Next[i]){ int v=ver[i]; if(vis[v]) continue; sz=0,len[v]=1,sum[v]=val[v]; getdep(v,u); 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]=val[v]; getdep1(v,u); 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[u]==a[pos]) ++cnt[pos]; } for(int j=1;j<=sz1;++j){ int t=st1[j];int pos=(len[t])%m+1; if(val[u]==a1[pos]) ++cnt1[pos]; } } } void solve(int u){ calc(u),vis[u]=1;int totsz=size[u]; for(int i=head[u];i;i=Next[i]){ int v=ver[i]; if(vis[v]) continue; rt=0; n1=size[v]; if(n1<m) continue; findrt(v,u); solve(rt); } } int main(){ 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(head,0,sizeof(head)); 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 u=read(),v=read();add(u,v); } 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)); son[0]=inf,rt=0,n1=n; findrt(1,0); solve(rt); print(ans); } Ot(); return 0; }
相关文章推荐
- bzoj 4598: [Sdoi2016]模式字符串 (hash+点分治)
- bzoj 4598: [Sdoi2016]模式字符串 点分治+hash
- BZOJ4598: [Sdoi2016]模式字符串
- BZOJ 4598: [Sdoi2016]模式字符串
- [SDOI2016] 模式字符串 (BZOJ4598 & VIJOS1995)
- 【BZOJ 4598】【SDOI 2016 Round2 Day1 T3】模式字符串
- [BZOJ4598][Sdoi2016]模式字符串(点分治+Hash)
- bzoj4598 [Sdoi2016]模式字符串 hash+点分
- bzoj4598 [Sdoi2016]模式字符串(hash+点分治)
- 4598: [Sdoi2016]模式字符串
- 【BZOJ4598】[Sdoi2016]模式字符串 树分治+hash
- 【LOJ】#2065. 「SDOI2016」模式字符串
- bzoj4598: [Sdoi2016]模式字符串
- 字符串的模式匹配(BF、KMP)
- tp 3.2 组合查询, 字符串模式查询
- 【BZOJ 2121】字符串游戏
- sed 多行替换,多行模式处理字符串;一次替换
- Linux shell 字符串模式匹配运算符
- KMP字符串模式匹配详解
- KMP字符串模式匹配详解