zoukankan      html  css  js  c++  java
  • P4075 [SDOI2016]模式字符串

    题目

    P4075 [SDOI2016]模式字符串

    求树上两点对数量,满足其路径上结点的字符连接起来是串 (S) 可以循环得到的。

    分析

    首先这类树上统计点对,还有字符串的,通常,因为我们的点分治需要拼接,所有这样的题也一般是 点分治+字符串哈希 来完成。

    这道题就是要拼接两个串,那么我们其实就可以用字符串哈希来拼接。

    首先对于每一个串,如果它能成为我们循环串循环无穷次后的一个前缀/后缀,它才有可能拼接。

    其次,我们可以把这一些串按照 (m) 个来划分,也就是模 (m) 意义下。

    那么剩下的其实就是分别对于前缀和后缀进行模意义下的路径数个数,和P2634 [国家集训队]聪聪可可类似。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    template <typename T>
    inline void read(T &x){
        x=0;char ch=getchar();bool f=false;
        while(!isdigit(ch)) f|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=f?-x:x;return;
    }
    template <typename T>
    inline void write(T x){
        if(x<0) putchar('-'),x=-x;
        if(x>9) write(x/10);
        putchar(x%10^48);
    	return;
    }
    #define ll long long
    const int N=2e5+5,INF=1e9+7,MOD=1e9+7;
    const ll base=31;
    int n,m,k,t,Ans;
    int head[N],to[N],nex[N],idx;
    inline void add(int u,int v){
    	nex[++idx]=head[u];
    	to[idx]=v;
    	head[u]=idx;
    	return ;
    }
    char a[N],s[N];
    ll pre[N],suf[N];
    int PathCnt,siz[N],dep[N],FMax,Max,Root,Size;
    int Sum[N][2],Num[N][2];
    bool vis[N];
    void GetRoot(int x,int fa){
    	siz[x]=1;int Max=0;
    	for(int i=head[x];i;i=nex[i]){
    		int y=to[i];
    		if(y==fa||vis[y]) continue;
    		GetRoot(y,x);siz[x]+=siz[y];
    		Max=max(Max,siz[y]);
    	}
    	Max=max(Max,Size-siz[x]);
    	if(Max<FMax) FMax=Max,Root=x; 
    	return ;
    }
    void GetPath(int x,ll Hash,int depth,int fa){
    	Hash=(Hash*base+a[x]-'A')%MOD;
    	dep[x]=depth;
    	if(Hash==pre[depth]) Num[(depth-1)%m+1][0]++,Ans+=Sum[m-(depth-1)%m][1];
    	if(Hash==suf[depth]) Num[(depth-1)%m+1][1]++,Ans+=Sum[m-(depth-1)%m][0];
    	for(int i=head[x];i;i=nex[i]){
    		int y=to[i];
    		if(vis[y]||y==fa) continue;
    		GetPath(y,Hash,depth+1,x);
    		dep[x]=max(dep[x],dep[y]);
    	}
    	return ;
    }
    void DFS(int x){
    	vis[x]=true;
    	int len=0;
    	Sum[1][0]=Sum[1][1]=1;
    	for(int i=head[x];i;i=nex[i]){
    		int y=to[i];
    		if(vis[y]) continue;
    		GetPath(y,a[x]-'A',2,x);
    		int Maxdep=min(dep[y],m);len=max(len,Maxdep);
    		for(int j=1;j<=Maxdep;j++) Sum[j][0]+=Num[j][0],Sum[j][1]+=Num[j][1],Num[j][0]=Num[j][1]=0;
    	}
    	for(int i=1;i<=len;i++) Sum[i][0]=Sum[i][1]=0;
    	for(int i=head[x];i;i=nex[i]){
    		int y=to[i];
    		if(vis[y]) continue;
    		Size=FMax=siz[y],Root=0,GetRoot(y,x),DFS(Root);
    	}
    	vis[x]=false;
    	return ;
    }
    int main(){
    	int t;
    	read(t);
    	while(t--){
    		memset(head,0,sizeof(head));idx=Ans=0;
    		read(n),read(m);
    		scanf("%s",a+1);
    		for(int i=1;i<n;i++){
    			int u,v;
    			read(u),read(v),add(u,v),add(v,u);
    		}
    		scanf("%s",s+1);
    		ll tmp=1;
    		for(int i=1;i<=n;i++){
    			pre[i]=(pre[i-1]+tmp*(s[(i-1)%m+1]-'A')%MOD)%MOD;
    			suf[i]=(suf[i-1]+tmp*(s[m-(i-1)%m]-'A')%MOD)%MOD;
    			tmp=tmp*base%MOD;
    		}
    		Root=0,Size=FMax=n,GetRoot(1,0),DFS(Root);
    		write(Ans),putchar('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    Kefa and Park
    分土地
    果园里的树
    分解质因数
    素数筛
    cantor的数表
    new一个二维数组
    基础练习 十六进制转八进制
    查函数功能
    concatenate函数
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14726851.html
Copyright © 2011-2022 走看看