E - Star MST(组合数学+DP)

30 篇文章 1 订阅
18 篇文章 0 订阅

E - Star MST

分析:

  • 组合数学 + DP

  • 只需要给出根节点出发的n-1条边的长度,剩下的边的长度,就是由这些边推出来的

    具体原理详见大佬

  • d p [ i ] [ j ] dp[i][j] dp[i][j] 表示前i条边,最大边j时的方案(总数

#include <bits/stdc++.h>
#define int long long 
#define Pa pair<int,int> 
using namespace std;

const int N=255, mo=998244353;
int ksm(int a,int b,int p=mo,int res=1)
{
    for( ; b ; a=a*a%p, b>>=1) if(b&1) res=res*a%p;
    return res; 
}
int fac[N],inv[N];
void init(int n=N-2)
{
    inv[0]=fac[0]=1;
    for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mo;
    inv[n]=ksm(fac[n],mo-2);
    for(int i=n-1;i>=1;i--) inv[i]=inv[i+1]*(i+1)%mo;
}
int C(int n,int m)
{
    return fac[n]*inv[m]%mo*inv[n-m]%mo;
}
int dp[N][N];
void solve()
{
    init();
    int n,k; 
    cin>>n>>k;
    dp[0][0]=1;
    for(int i=0;i<n;i++)
    {
        for(int j=1;j<=k;j++)
        {
            for(int t=0;t+i<n;t++)
            {
                (dp[i+t][j]+=dp[i][j-1]*C(n-1-i,t)%mo*ksm(k-j+1,t*i+t*(t-1)/2))%=mo;
                //这一状态表示将要选取t个j,对于这t个j有n-1-i个位置能占
                //t*i:每添加1条边会跟之前的i个便分别连线
                //t*(t-1)/2:新加的边互相之间也会有连边
                //连边的大小[j+1,k]:k-j+1种方案数
            }
        }
    }
    cout<<dp[n-1][k];
}
signed main()
{
    int T=1;
    //cin>>T;
    while(T--) solve();
}

solution 2:

  • 分析见上文的“大佬”
#include <bits/stdc++.h>
#define int long long 
#define Pa pair<int,int> 
using namespace std;

const int N=255, mo=998244353;
int ksm(int a,int b,int p=mo)
{
    int res=1;
    while(b)
    {
        if(b&1) res=res*a%p;
        b>>=1; a=a*a%p;
    }
    return res;
}
int inv[N], pw[N][N*N];
void init(int n=N-3)
{
    inv[0]=inv[1]=1;
    for(int i=2;i<=n;i++) inv[i]=(mo-mo/i)*inv[mo%i]%mo;
    for(int i=2;i<=n;i++) inv[i]=inv[i]*inv[i-1]%mo;
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=n*n;j++) pw[i][j]=ksm(i,j); 
    }
}
int dp[N][N];
void solve()
{
    init();
    int n,k;
    cin>>n>>k;
    dp[0][0]=1;
    for(int i=1;i<=n;i++) for(int j=1;j<=k;j++)
        for(int p=0;p<i;p++) for(int t=0;t<j;t++)
        {
            (dp[i][j]+=dp[p][t]*pw[k-j+1][(p+i-1)*(i-p)/2]%mo*inv[i-p])%=mo;
        }
    
    int ans=0;
    for(int i=1;i<=k;i++)
    {
        (ans+=dp[n-1][i])%=mo;
    }
    for(int i=2;i<n;i++) ans=ans*i%mo;
    cout<<ans<<"\n"; 
}
signed main()
{
    int T=1;
    //cin>>T;
    while(T--) solve();
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yezzz.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值