zoukankan      html  css  js  c++  java
  • 【JZOJ4816】【NOIP2016提高A组五校联考4】label

    题目大意:有一棵(n)个点的树,你要给每个点赋一个([1,m])内的整数权值,使得相邻两个点的权值差至少为(k),问方案数。
    (n,kleq 100,mleq 10^9)

    Solution

    (f[i][j])表示(i)为根的子树满足条件,而(i)的权值为(j)的方案数,转移用前缀和优化。
    通过打表可以发现(f[i][j])是对称的,即(f[i][j]=f[i][m-j+1]),并且左边最多有((n-1)*k)个不同的数,中间的一段都是相同的。于是我们记录前((n-1)*k)个状态,以及(pos[i])表示从哪一位开始都是相同的,就能(O(1))求出前缀和了。

    Code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    typedef long long ll;
    const int N=107,M=10017;
    const ll P=1000000007;
    
    int T,n,m,k;
    ll f[N][M],s[N][M],pos[N];
    
    int tot,st[N],to[N<<1],nx[N<<1];
    void add(int u,int v){to[++tot]=v,nx[tot]=st[u],st[u]=tot;}
    
    ll sum(int u,int j){
    	ll ret=0;
    	if(j<=10010)return s[u][j];
    	else if(j<pos[u])return s[u][j];
    	else{
    		ret=(ret+s[u][pos[u]-1])%P;
    		if(j<=m-pos[u]+1)ret=(ret+f[u][pos[u]]*(j-pos[u]+1)%P)%P;
    		else{
    			ret=(ret+f[u][pos[u]]*(m-2*pos[u]+2)%P)%P;
    			ret=(ret+s[u][pos[u]-1]-s[u][m-j]+P)%P;
    		}
    		return ret;
    	}
    }
    
    void dfs(int u,int from){
    	for(int i=st[u];i;i=nx[i])if(to[i]!=from)dfs(to[i],u);
    	for(int j=1;j<=10010&&j<=m;++j){
    		f[u][j]=1;
    		for(int i=st[u];i;i=nx[i])if(to[i]!=from){
    			if(k==0)f[u][j]=f[u][j]*sum(to[i],m)%P;
    			else{
    				ll tmp=0;
    				if(j-k>0)tmp=(tmp+sum(to[i],j-k))%P;
    				if(j+k<=m)tmp=(tmp+sum(to[i],m)-sum(to[i],j+k-1)+P)%P;
    				f[u][j]=f[u][j]*tmp%P;
    			}
    		}
    	}
    	for(int j=1;j<=10010&&j<=m;++j)if(f[u][j]==f[u][j+1]){pos[u]=j;break;}
    	for(int j=1;j<=10010&&j<=m;++j)s[u][j]=(s[u][j-1]+f[u][j])%P;
    }
    
    int main(){
    	freopen("label.in","r",stdin);
    	//freopen("label.out","w",stdout);
    	scanf("%d",&T);
    	while(T--){
    		tot=0;
    		memset(st,0,sizeof(st));
    		memset(f,0,sizeof(f));
    		memset(s,0,sizeof(s));
    		memset(pos,0,sizeof(pos));
    		memset(to,0,sizeof(to));
    		memset(nx,0,sizeof(nx));
    		scanf("%d%d%d",&n,&m,&k);
    		for(int i=1,u,v;i<n;++i)scanf("%d%d",&u,&v),add(u,v),add(v,u);
    		dfs(1,0);
    		printf("%lld
    ",sum(1,m));
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    jdbc和DBeaver客户端连接oracle很慢,初始化连接成功后速度正常
    centos7中vncserver连接失败
    postgres数据库建库、修改owner
    nested exception is org.apache.ibatis.binding.BindingException:
    postgresql导出表insert方式数据
    解决ecllipse注释模板不生效问题
    postgresql 修改表属性,包括新增、修改、删除列
    ssh本机可登陆远端服务器,但远端服务器无法登陆本机
    linux源码安装后,设置动态库路径和环境变量
    valgrind跟踪调试动态库*.so
  • 原文地址:https://www.cnblogs.com/zjlcnblogs/p/12055053.html
Copyright © 2011-2022 走看看