CF1097G Vladislav and a Great Legend

首先答案为

\[\sum\limits_{T}(|T|-1)^k2^{T中度数大于1的点数} \]

这个\(T\)枚举的是这个虚树,\(T\)中度数为\(1\)的点必须在点集里,否则虚树会更小。其他点在不在无所谓,所以系数是这个。把\((|T|-1)^k\)用第二类斯特林数展开成下降幂变成

\[\sum\limits_{i=0}^k\begin{Bmatrix}k\\i\end{Bmatrix}i!\sum\limits_T2^{度数大于1}C(|T|-1,i) \]

后面那个\(C(|T|-1,i)\)的组合意义为在这棵虚树的所有边里选择\(i\)个的方案数。那么对于一个\(i\)后面那个求和符号意义即为从这个树里选择一个连通块,再从这个连通块里选择\(i\)条边的方案数。就可以考虑设\(dp[i][j][0/1/2]\)表示以\(i\)为根,连通块里选择了\(j\)条边,\(i\)号节点的度数为\(0\)或\(1\)或大于等于\(2\)。转移的时候决策这条边是否被选到虚树里,是否被选择。这个第三维是为了看合并两个子树这两根是否从叶子变成了非叶子。转移就用树上背包经典的上界优化即可做到\(O(nk)\)。这个dp第三维在转移的时候\(0\)和\(2\)其实可以合并,所以常数也还可以。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
#define N 100004
const int p=1e9+7;
struct edge{int to,nxxt;}e[N<<1];
int n,k,head[N],cnt=1,dp[N][202][3],fac[N],s[202][202],tf[202][3],siz[N];
inline void upd(int &x,int y){x+=x+y>=p?y-p:y;}
inline void ins(int u,int v){e[cnt]=(edge){v,head[u]};head[u]=cnt++;}
void df5(int te,int la)
{dp[te][0][0]=1;siz[te]=0;
    for(int i=head[te];i;i=e[i].nxxt)
    {int j=e[i].to;if(j==la)continue;df5(j,te);
        int mx=min(k,siz[te]+siz[j]+1);
        for(int ii=0;ii<=mx;ii++)tf[ii][0]=tf[ii][1]=tf[ii][2]=0;
        int mx1=min(k,siz[te]),mx2=min(k,siz[j]);
        for(int ii=0;ii<=mx1;ii++)for(int jj=0;jj<=mx2&&ii+jj<=k;jj++)
        {int nv=(dp[j][jj][0]+dp[j][jj][2])%p;
            upd(tf[ii+jj][1],1ll*dp[te][ii][0]*nv%p);
            upd(tf[ii+jj][1],2ll*dp[te][ii][0]*dp[j][jj][1]%p);
            upd(tf[ii+jj][2],2ll*dp[te][ii][1]*nv%p);
            upd(tf[ii+jj][2],4ll*dp[te][ii][1]*dp[j][jj][1]%p);
            upd(tf[ii+jj][2],1ll*dp[te][ii][2]*nv%p);
            upd(tf[ii+jj][2],2ll*dp[te][ii][2]*dp[j][jj][1]%p);
            upd(tf[ii+jj+1][1],1ll*dp[te][ii][0]*nv%p);
            upd(tf[ii+jj+1][1],2ll*dp[te][ii][0]*dp[j][jj][1]%p);
            upd(tf[ii+jj+1][2],2ll*dp[te][ii][1]*nv%p);
            upd(tf[ii+jj+1][2],4ll*dp[te][ii][1]*dp[j][jj][1]%p);
            upd(tf[ii+jj+1][2],1ll*dp[te][ii][2]*nv%p);
            upd(tf[ii+jj+1][2],2ll*dp[te][ii][2]*dp[j][jj][1]%p);
        }
        siz[te]+=siz[j]+1;
        for(int ii=0;ii<=min(siz[te],k);ii++)upd(dp[te][ii][0],tf[ii][0]),
        upd(dp[te][ii][1],tf[ii][1]),upd(dp[te][ii][2],tf[ii][2]);
    }
}
int main()
{
	scanf("%d%d",&n,&k);
    for(int i=1;i<n;i++){int x,y;scanf("%d%d",&x,&y);ins(x,y),ins(y,x);}
    df5(1,1);fac[0]=1;for(int i=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%p;
    s[0][0]=1;
    for(int i=1;i<=k;i++)for(int j=1;j<=i;j++)s[i][j]=(s[i-1][j-1]+1ll*s[i-1][j]*j%p)%p;
    int ans=0;
    for(int i=0;i<=k;i++)
    {int su=0;
        for(int j=1;j<=n;j++)
        {
            upd(su,dp[j][i][0]);upd(su,dp[j][i][1]);upd(su,dp[j][i][2]);
        }
        upd(ans,1ll*su*s[k][i]%p*fac[i]%p);
    }
    printf("%d\n",ans);
}
上一篇:写作(1~3)


下一篇:Codeforces 1097G - Vladislav and a Great Legend(第二类斯特林数+树上背包)