CF1097G Vladislav and a Great Legend

Link
首先Stirling数拆一下自然数幂得到\(ans=\sum\limits_{i=0}^n\left\{_i^k\right\}i!\sum\limits_{X\ne\varnothing}{f(X)\choose i}\)
\({f(X)\choose i}\)就是在\(X\)的Steiner树中选\(i\)条边的方案数。
考虑树形dp来算这个东西,强制\(X\)的Steiner树的根是\(X\)中最浅的点。
\(f_{u,i}\)表示\(u\)的子树中的所有点集的Steiner树选\(i\)条边的方案数之和,考虑如何从\(u\)的儿子\(v\)转移到\(u\),分点集的情况以及\((u,v)\)是否选讨论:
\(t\)为合并\(v\)之前的\(f_u\)
\(1.\)点集中的点都不在\(v\)的子树中:\(\forall i\in[0,\min(size_v,k)],f_{u,i}+=t_i\)
\(2.1\)点集包含\(u\),且除此之外的点都在\(v\)的子树中,\((u,v)\)不选:\(\forall i\in[0,\min(size_v,k)],f_{u,i}+=f_{v,i}\)
\(2.2\)点集包含\(u\),且除此之外的点都在\(v\)的子树中,\((u,v)\)被选:\(\forall i\in[1,\min(size_v,k)],f_{u,i}+=f_{v,i-1}\)
\(3.1\)点集横跨\(u\)的其它子树以及\(v\)的子树,\((u,v)\)不选:\(\forall i\in[0,\min(k,size_v)],j\in[0,\min(k-i,size_u)],f_{u,i+j}+=t_if_{v,j}\)
\(3.2\)点集横跨\(u\)的其它子树以及\(v\)的子树,\((u,v)\)被选:\(\forall i\in[0,\min(k,size_v)],j\in[0,\min(k-i,size_u)],f_{u,i+j+1}+=t_if_{v,j}\)
\(3.2\)中多转移的直接无视就好了)
注意实时更新\(size\),同时记录一下\(sum_i\)表示所有点集的Steiner树选\(i\)条边的方案数之和,最后算出答案就好了。
时间复杂度是\(O(nk)\)的。

#include
#include
#include
#include
const int N=100007,M=207,P=1000000007;
namespace IO
{
    char ibuf[(1<<21)+1],*iS,*iT;
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
}
using IO::read;
int min(int a,int b){return a>31&P);}
int inc(int a,int b){return mod(a+b-P);}
int dec(int a,int b){return mod(a-b);}
int mul(int a,int b){return 1ll*a*b%P;}
std::vectore[N];int n,k,ans,fac[M],S[M][M],f[N][M],size[N],t[M],sum[M];
void dfs(int u,int fa)
{
    size[u]=1,f[u][0]=1;
    for(int v:e[u])
    {
    if(v==fa) continue;
    dfs(v,u),memcpy(t,f[u],(k+1)<<2),f[u][0]=inc(f[u][0],f[v][0]);
    for(int i=1;i<=min(k,size[v]);++i) f[u][i]=inc(f[u][i],inc(f[v][i],f[v][i-1]));
    for(int i=0;i<=min(k,size[u]);++i)
        for(int j=0,x;j<=min(k-i,size[v]);++j)
        x=mul(t[i],f[v][j]),f[u][i+j]=inc(f[u][i+j],x),sum[i+j]=inc(sum[i+j],x),f[u][i+j+1]=inc(f[u][i+j+1],x),sum[i+j+1]=inc(sum[i+j+1],x);
    size[u]+=size[v];
    }
}
int main()
{
    n=read(),k=read(),fac[0]=1,S[1][1]=1;
    for(int i=1;i<=k;++i) fac[i]=mul(fac[i-1],i);
    for(int i=2;i<=k;++i) for(int j=1;j<=k;++j) S[i][j]=inc(S[i-1][j-1],mul(S[i-1][j],j));
    for(int i=1,u,v;i

你可能感兴趣的:(CF1097G Vladislav and a Great Legend)