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);
    	}
    }
    
  • 相关阅读:
    eclipse如何与git 配合工作。
    git托管代码(二)
    PPC2003 安装 CFNET 3.5成功
    我的Window Mobile WCF 項目 第三篇 WM窗体设计
    我的Window Mobile WCF 項目 第一篇Mobile开发和WinForm开发的区别
    我的Window Mobile WCF 項目 第七天
    我的Window Mobile WCF 項目 第二篇 WindowsMobile访问WCF
    WCF 用vs2010 和 vs2008的简单对比测试
    vs2010beta1 和 搜狗输入法 冲突,按下 Ctrl 键就报错,重装搜狗解决
    我的Window Mobile WCF 項目 第六天 (二)
  • 原文地址:https://www.cnblogs.com/f321dd/p/6490066.html
Copyright © 2011-2022 走看看