【Codeforces】 CF1097G Vladislav and a Great Legend

题目链接

CF方向
Luogu方向

题目解法

首先一个套路是普通幂转下降幂(为什么?因为观察到 k k k 很小,下降幂可以转化组合数问题,从而 d p dp dp 求解)

即 f ( X ) k = ∑ i = 0 k { k i } i ! ( f ( X ) i ) f(X)^k=\sum\limits_{i=0}^{k}{k\brace i}i!\binom{f(X)}{i} f(X)k=i=0∑k{ik}i!(if(X))

现在的问题是对于所有生成树求出中间选 i i i 条边的方案数

我们令非空顶点的点集为关键点,其他生成树上的点为包含点

考虑树形 d p dp dp,令 f i , j f_{i,j} fi,j 表示在 i i i 的子树中选出至少 1 1 1 个关键点,且与 i i i 连通的生成树中选出 j j j 条边的方案数

考虑转移:

  1. v v v 子树中没有关键点
    f u , i → f u , i f_{u,i}\to f_{u,i} fu,i→fu,i,不能计入答案计算,因为没有改变关键点集合
  2. 只有 v v v 子树中的关键点组成
    f v , i + f v , i − 1 → f u , i f_{v,i}+f_{v,i-1}\to f_{u,i} fv,i+fv,i−1→fu,i,不能计入答案计算,因为这个关键点集合在 v v v 时已经计算过
  3. u , v u,v u,v 子树中均有关键点
    f u , i ∗ f v , j → f u , i + j & f u , i + j + 1 f_{u,i}*f_{v,j}\to f_{u,i+j}\&f_{u,i+j+1} fu,i∗fv,j→fu,i+j&fu,i+j+1,可以计入答案计算,因为改变了关键点集合

根据树形 d p dp dp 的时间复杂度计算,时间复杂度为 O ( n k ) O(nk) O(nk)

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=100100,K=210,P=1e9+7;
int n,k,siz[N],s2[K][K],t[N],ans[N];
int ne[N<<1],e[N<<1],h[N],idx;
int f[N][K];
inline int read(){
    int FF=0,RR=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
    for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
    return FF*RR;
}
inline void add(int x,int y){ e[idx]=y,ne[idx]=h[x],h[x]=idx++;}
inline void inc(int &x,int y){ x+=y;if(x>=P) x-=P;}
void dfs(int u,int fa){
    siz[u]=1,f[u][0]=1;
    for(int i=h[u];~i;i=ne[i]){
        int v=e[i];if(v==fa) continue;
        dfs(v,u);
        for(int j=0;j<=k;j++) t[j]=f[u][j];
        for(int j=0;j<=k;j++){
            inc(t[j],f[v][j]);
            if(j) inc(t[j],f[v][j-1]);
        }
        for(int p=0,mxp=min(k,siz[u]);p<=mxp;p++) for(int q=0,mxq=min(k-p,siz[v]);q<=mxq;q++){
            int coef=1ll*f[u][p]*f[v][q]%P;
            inc(t[p+q],coef),inc(t[p+q+1],coef);
            inc(ans[p+q],coef),inc(ans[p+q+1],coef);
        }
        siz[u]+=siz[v];
        for(int j=0;j<=k;j++) f[u][j]=t[j];
    }
}
int main(){
    n=read(),k=read();
    s2[0][0]=1;
    for(int i=1;i<=k;i++) for(int j=1;j<=i;j++) s2[i][j]=(s2[i-1][j-1]+1ll*s2[i-1][j]*j)%P;
    memset(h,-1,sizeof(h));
    for(int i=1;i<n;i++){
        int x=read(),y=read();
        add(x,y),add(y,x);
    }
    dfs(1,-1);
    int ANS=0;
    for(int i=1,fac=1;i<=k;i++,fac=1ll*fac*i%P) ANS=(ANS+1ll*ans[i]*s2[k][i]%P*fac)%P;
    printf("%d\n",ANS);
    return 0;
}
相关推荐
小O的算法实验室14 小时前
2026年ESWA,自适应基于排序的协同进化学习粒子群算法+边缘计算服务器部署,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
cpp_250114 小时前
P1832 A+B Problem(再升级)
数据结构·c++·算法·动态规划·题解·洛谷·背包dp
꧁细听勿语情꧂14 小时前
合并两个有序表、判断链表的回文结构、相交链表、环的链表一和二
c语言·开发语言·数据结构·算法
木井巳14 小时前
【递归算法】解数独
java·算法·leetcode·决策树·深度优先·剪枝
大肥羊学校懒羊羊15 小时前
完数与盈数的计算题解
数据结构·c++·算法
阿Y加油吧15 小时前
算法实战笔记:LeetCode 31 下一个排列 & 287 寻找重复数
笔记·算法·leetcode
穿条秋裤到处跑15 小时前
每日一道leetcode(2026.04.24):距离原点最远的点
算法·leetcode·职场和发展
wayz1115 小时前
Day 13 编程实战:朴素贝叶斯与极端涨跌预警
人工智能·算法·机器学习
叶小鸡15 小时前
小鸡玩算法-力扣HOT100-贪心算法
算法·leetcode·贪心算法
Old Uncle Tom15 小时前
提示词编写规范
数据库·算法