[CF913F]Strongly Connected Tournament

Description

太长了自己看
相信各位打过Hello 2018的dalao都知道题意我就不多讲了。

Solution

这道题比赛时没想真是亏了。。。
首先根据一些竞赛图相关姿势我们知道汉密尔顿回路唯一且一定存在,那么这个条件就没有用了
然后让我们来慢慢套路。
首先设Fn表示n个点的答案,枚举n所在的强联通分量的大小,我们可以得到:

F[n]=i=1n(F[ni]+F[i]+i(i1)2+(ni)i)G[i]Cp[n][i]

G[i]表示i个点内部打成强联通分量的概率
Cp[n][i]表示从n个点中输出i个点的概率(输的点之间不互相计算)
接下来考虑G[n]如何计算,直接计算可能比较麻烦,我们可以考虑容斥,枚举n所在的强联通分量的大小
G[n]=1i=1n1G[i]Cp[n][i]

那么我们只需要考虑如何求解Cp[n][m]了,考虑新加入一个点是否被输出来
Cp[n][m]=Cp[n1][m](1p)m+Cp[n1][m1]pnm

然后这道题就做完了,真是满满的计数题的套路23333

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

typedef long long ll;

const int N=2*1e3+5,Mo=998244353;

int pwr(int x,int y) {
    int z=1;
    for(;y;y>>=1,x=(ll)x*x%Mo)
        if (y&1) z=(ll)z*x%Mo;
    return z;
}

int n,a,b,p,q,P[N],Q[N],Cp[N][N],G[N],F[N];

int main() {
    scanf("%d",&n);
    scanf("%d%d",&a,&b);
    int p=(ll)a*pwr(b,Mo-2)%Mo,q=Mo+1-p;
    P[0]=1;fo(i,1,n) P[i]=(ll)P[i-1]*p%Mo;
    Q[0]=1;fo(i,1,n) Q[i]=(ll)Q[i-1]*q%Mo;
    Cp[0][0]=1;
    fo(i,1,n) {
        Cp[i][0]=1;
        fo(j,1,i) Cp[i][j]=((ll)Cp[i-1][j]*Q[j]%Mo+(ll)Cp[i-1][j-1]*P[i-j]%Mo)%Mo;
    }
    G[1]=1;
    fo(i,2,n) {
        G[i]=1;
        fo(j,1,i-1) (G[i]+=Mo-(ll)G[j]*Cp[i][j]%Mo)%=Mo;
    }
    F[1]=0;
    fo(i,2,n) {
        fo(j,1,i-1) {
            int now=0;
            (now+=F[i-j]+F[j])%=Mo;
            (now+=j*(j-1)/2)%=Mo;
            (now+=(i-j)*j)%=Mo;
            (F[i]+=(ll)now*G[j]%Mo*Cp[i][j]%Mo)%=Mo;
        }
        (F[i]+=(ll)i*(i-1)/2*G[i]%Mo*Cp[i][i]%Mo)%=Mo;
        F[i]=(ll)F[i]*pwr(1+Mo-(ll)G[i]*Cp[i][i]%Mo,Mo-2)%Mo;
    }
    printf("%d\n",F[n]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值