zoukankan      html  css  js  c++  java
  • JZOJ6407. 【NOIP2019模拟11.05】小 D 与随机

    Description

    在这里插入图片描述
    n<=5000n<=5000

    Solution

    • 神仙计数题。
    • 考虑树形DP。
    • 为了DP的方便,有一种很骚的操作,因为是对于每一个恰好为c个好点的状态求kck^c,我们为了复杂度不好记录c。
    • 但是我们可以将它转化为至少c个好点
      kc=(k1+1)c=i=0cCci(k1)i1ci=i=0cCci(k1)ik^c=(k-1+1)^c=sum_{i=0}^{c}C_c^i*(k-1)^i*1^{c-i}=sum_{i=0}^{c}C_c^i*(k-1)^i
    • 考虑对于每一个合法的好点的选择方案,枚举它的子集,每一个子集的贡献就只用当作(k1)i(k-1)^i,只用我们将k变成k-1,将它当作每多一个好点的贡献进行转移就好了。
    • f[x][j]f[x][j]表示x的子树内,以1~size[x]给它们编号之后,最小的好点的编号为j。
    • 合并的时候类似树形依赖背包,枚举当前size和儿子的size,将它们合并在一起。具体来说就是讨论哪一个里面的最小的好点合并后是最小的,并考虑小于它的点有多少个以及插入的方案数。
    • 注意并不是儿子里面都一定有好点,有可能儿子里没有好点,因为状态没有记录这个东西,所以要单独计算。
    • 最好考虑当前的根是否是好点,对于f[x][i]首先要插在i前面,如果是好点的话要求一个后缀和,当然也要特殊计算儿子里面没有好点,当前根单独一个好点的情况。
    • 最后要考虑整棵树都没有好点的贡献。
    • 具体细节很多。
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define maxn 5005
    #define ll long long 
    #define mo 998244353
    using namespace std;
    
    int n,i,j,k,x,y;
    int em,e[maxn*2],nx[maxn*2],ls[maxn];
    ll ans,K,Kp,C[maxn][maxn],fct[maxn];
    
    void insert(int x,int y){
    	em++; e[em]=y; nx[em]=ls[x]; ls[x]=em;
    	em++; e[em]=x; nx[em]=ls[y]; ls[y]=em;
    }
    
    int sz[maxn],p,q; ll f[maxn][maxn],g[maxn],s0[maxn],s1[maxn];
    void dp(int x,int y){
    	for(j=0;j<=sz[x];j++) g[j]=f[x][j];
    	s0[sz[x]+1]=fct[sz[x]];
    	for(j=sz[x];j>=1;j--) s0[j]=(s0[j+1]+f[x][j])%mo;
    	s1[sz[y]+1]=fct[sz[y]];
    	for(j=sz[y];j>=1;j--) s1[j]=(s1[j+1]+f[y][j])%mo;
    	for(j=0;j<=sz[x]+sz[y];j++) f[x][j]=0;
    	for(p=1;p<=sz[x];p++) for(k=0;k<=sz[y];k++)
    		f[x][p+k]+=C[p+k-1][p-1]*C[sz[x]+sz[y]-p-k][sz[x]-p]%mo*g[p]%mo*s1[k+1]%mo;
    	for(q=1;q<=sz[y];q++) for(k=0;k<=sz[x];k++)
    		f[x][q+k]+=C[q+k-1][q-1]*C[sz[x]+sz[y]-q-k][sz[y]-q]%mo*f[y][q]%mo*s0[k+1]%mo;
    	sz[x]+=sz[y];
    	for(j=1;j<=sz[x];j++) f[x][j]%=mo;
    }
    
    void dfs(int x,int p){
    	for(int i=ls[x];i;i=nx[i]) if (e[i]!=p)
    		dfs(e[i],x),dp(x,e[i]);
    	sz[x]++;
    	ll sum=0;
    	for(int j=sz[x];j;j--) {
    		(sum+=f[x][j])%=mo;
    		f[x][j]=(f[x][j-1]*(j-1)%mo+sum*K%mo+fct[sz[x]-1]*K%mo)%mo;
    	} 
    }
    
    int main(){
    	scanf("%d%lld",&n,&K),K--;
    	for(i=1;i<n;i++) scanf("%d%d",&x,&y),insert(x,y);
    	C[0][0]=1,fct[0]=1;
    	for(i=1;i<=n;i++){
    		C[i][0]=1,fct[i]=fct[i-1]*i%mo;
    		for(j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mo;
    	}
    	dfs(1,0);
    	ll ans=fct[n];
    	for(i=1;i<=n;i++) ans+=f[1][i];
    	printf("%lld",ans%mo);
    }
    
    
  • 相关阅读:
    管理 node 版本,选择 nvm 还是 n?
    JDBC性能优化方案
    JDBC基础-setFetchSize方法
    JDBC的fetchsize和maxrows
    正确使用MySQL JDBC setFetchSize()方法解决JDBC处理大结果
    10种简单的Java性能优化
    35+ 个 Java 代码性能优化总结
    一线架构师带你玩性能优化
    诊断Java代码中常见的数据库性能热点问题应该这么做!
    十个 JDBC 的最佳实践
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/13090920.html
Copyright © 2011-2022 走看看