zoukankan      html  css  js  c++  java
  • [SDOI2016] 模式字符串 (BZOJ4598 & VIJOS1995)

    首先直接点分+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[N];
    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[N],f1[N],f2[N],f3[N],f4[N];
    bool vis[N];
    char t1[N],t2[N];
    ll c1[N],c2[N];
    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
    ",ans);
    	}
    }
    
  • 相关阅读:
    ASPxGridView控件的基本属性
    未整理笔记
    ASPxGridView中Command列自定义按钮点击事件概要
    Cookie的使用
    ASPxGridView行的选中和行的焦点
    改变“骨感”,让OKR变得“丰满”
    高成就者的5个共同点
    项目的风险管理
    实际执行动作对OKR目标落地的重要性
    13种公认的高绩效习惯
  • 原文地址:https://www.cnblogs.com/f321dd/p/6490066.html
Copyright © 2011-2022 走看看