首页 > 技术文章 > codeforce Hello 2018 913F sol

rrsb 2018-01-18 13:17 原文

我们发现,一个大小为X的集合的答案和在里面的元素是无关的。那么我们用ans[n]表示大小为n时的答案。

我们考虑如何转移这个答案。 我们发现ans[0]=ans[1]=0;

我们考虑增量法,答案可以被拆成最后一个强连通分量和之前的那部分,我们给出以下转移式

 

strong[i]表示一个大小为i的点集有strong[i]的期望成为一个强联通分量。cp[s,i]表示s个人里面有i个人输给了其他s-i个人。

那么我们发现strong[i]*cp[s,i]=在s个点的集合中,最后i个构成一个强连通分量的可能性。

我们考虑一张缩点以后的图,这是一张DAG,那么我们总有一个点出度为0,我们不妨让其为最后一个强连通分量,我们发现cp[s,i]*strong[i]正好是存在这样一个强连通分量的概率。

我们考虑怎么求cp:cp(s, i) = cp(s - 1, i)·(1 - p)i + cp(s - 1, i - 1)·ps - i  

我们每次新加入一个点,有两种情况,这个点下标很大,对应cp(s - 1, i)·(1 - p)i    (因为他要全赢)

同理,这个下标小的时候,就是cp(s - 1, i - 1)·ps - i  

那么我们考虑如何求strong[i].

我们分析发现,. ,我们枚举最后一个强连通分量的大小,将其期望减去,剩下的就是要求的答案。

那么我们就做完了。

#include<bits/stdc++.h>
#define LL long long
#define sight(c) ('0'<=c&&c<='9')
#define mo 998244353
#define N 2007
inline void read(int &x){
    static char c;
    for (c=getchar();!sight(c);c=getchar());
    for (x=0;sight(c);c=getchar()) x=x*10+c-48;
}
LL qsm(LL x,LL y){
    static LL anw;
    for (anw=1;y;y>>=1,x=x*x%mo) if (y&1) anw=anw*x%mo;
    return anw;
}
using namespace std;
LL p,cp[N][N],s[N],ans[N];
int a,b,n;
int main () {
//    freopen("f.in","r",stdin);
    read(n);
    read(a); read(b); p=a*qsm(b,mo-2)%mo;
    cp[0][0]=1;
    for (int i=0;i<n;i++) 
      for (int j=0;j<=i;j++)    
        (cp[i+1][j]+=qsm(p,j)*cp[i][j]%mo)%=mo,
        (cp[i+1][j+1]+=qsm((mo+1-p)%mo,i-j)*cp[i][j]%mo)%=mo;
    s[1]=1;
    for (int i=1;i<=n;i++,s[i]=1)
     for (int j=1;j<i;j++)
      s[i]=((s[i]-s[j]*cp[i][j]%mo)%mo+mo)%mo;
    for (int i=2;i<=n;i++)     {
        for (int j=1;j<i;j++)
         ans[i]=ans[i]+s[j]*cp[i][j]%mo*
         (((ans[j]+ans[i-j])%mo+(j-1)*j/2+j*(i-j))%mo)%mo,
         ans[i]=ans[i]%mo;
        ans[i]=(ans[i]+i*(i-1)/2*s[i])%mo;
        ans[i]=ans[i]*qsm((mo+1-s[i])%mo,mo-2)%mo;
    }
    printf("%lld\n",ans[n]); return 0;
    
}

 

推荐阅读