[JZOJ5644]【NOI2018模拟4.10】随机定向

Description

给出一张 n个点的完全图,现在要给这个完全图的每一条边随机定向成一个有向图。对于一条边 ( i , j ) ( i < j ) ,这条边的方向是 i 到 j 的概率是 n u m i , j 10000 n u m i , j 指这条边旁边的数字,否则就是 j 到 i。在随机定向后,设这张有向图的强连通分量数目为 x,求 x × 10000 n ( n 1 ) 的期望,可以证明该期望值一定是一个整数。因为答案可能很大,所以只需要求出这个答案对 998244353取模后的结果。
只有m条边旁边有数字,其他边的概率都是1/2
n<=38,m<=19,w<=10000

Solution

完全图每条边定向,那么它就变成了一个竞赛图
竞赛图有一个非常好的性质,将它强联通分量缩点后,剩下的DAG的拓扑序列构成了唯一确定的一条链,链上每个强联通分量都向后面的所有强联通分量有边
(我也不会证)

我们定义割集(只在这道题中)为这条链的某一个间隙(包括第一个强联通分量前面的和最后一个后面的),这是一个边集(可以为空),它将所有点分成S和T两个集合,满足所有S与T之前的边方向都是从S到T

容易发现我们要求的强联通分量的个数就是割集个数-1
那么我们不妨直接统计割集

一种2^n*m的做法就出来了,枚举S集,计算边都是从这里连出去的概率

然而事实上我们发现只有m条边的概率不是1/2,我们将这些边成为特殊边

对于只有特殊边的割集,它们的贡献我们是可以直接计算的。
因此对于没有特殊边的情况,所有大小相同的S集对应的割集的概率都是一样的

考虑有特殊边的情况

我们先把所有边看做不是特殊边计入答案
然后再将特殊边的概率都乘上2,那就把之前的1/2消掉了

如果直接枚举特殊边的状态是不行的,有可能特殊边之间共用的端点会互相影响

那我们可以将特殊边组成的联通块弄出来,对于每个联通块枚举其中的点是在S中还是在T中

如果一个点没有与任何特殊边相连,那么将它看做单独一个点的联通块

容易发现这样的联通块点数最多为m+1

然后直接计算这个联通块的答案

最后,再将每个联通块的答案通过背包合并在一起,即可得到每种大小的联通块的答案了

具体可以参考标程
复杂度 O ( 2 m + 1 n + n 2 )

Code

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define N 39
#define LL long long
#define mo 998244353
using namespace std;
LL a[N][N],ans,cf,ny,f[N],g[N];
int n,m,cnt,a1[N][N],fr[N][2],cf2[22],a2[N][N],cny2[N*N];
bool bz[N][N],b[N];
void dfs(int k,int c)
{
    fr[k][0]=c;
    a1[c][++a1[c][0]]=k;
    fr[k][1]=a1[c][0];
    fo(i,1,n) if(!fr[i][0]&&a[k][i]!=5000) dfs(i,c);
}
int main()
{
    cin>>n>>m;
    if(n==1) 
    {
        printf("1\n");
        return 0;
    }
    fo(i,1,n) fo(j,i+1,n) a[i][j]=a[j][i]=5000;
    fo(i,1,m)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        a2[x][++a2[x][0]]=y;
        a2[y][++a2[y][0]]=x;
        scanf("%lld",&a[x][y]);
        a[y][x]=10000-a[x][y];
    }
    cf=1;
    ny=796898467;
    fo(i,1,n*(n-1)) cf=cf*(LL)10000%mo;
    ans=0;
    cf2[0]=1;
    fo(i,1,m+1) cf2[i]=cf2[i-1]*2; 
    fo(i,1,n) 
    {
        if(!fr[i][0]) dfs(i,++cnt);
    }
    g[0]=1;
    fo(i,1,cnt)
    {
        fo(j,0,n) f[j]=0;
        fo(l,0,cf2[a1[i][0]]-1)
        {
            int ct=0;
            LL s=1;
            fo(q,1,a1[i][0])
            {
                if(cf2[q-1]&l)
                {
                    ct++;
                    int k=a1[i][q];
                    fo(t,1,a2[k][0])
                    {
                        int p=a2[k][t];
                        if(fr[p][0]!=i) continue;
                        if(!(cf2[fr[p][1]-1]&l)) s=s*(LL)2%mo*a[k][p]%mo*ny%mo;
                    }   
                }
            }
            f[ct]=(f[ct]+s)%mo;
        }
        fod(j,n,0) 
        {
            LL v=0;
            fo(k,0,j)
            {
                v=(v+g[j-k]*f[k])%mo;
            }
            g[j]=v;
        }
    }
    ans=0;
    LL ny2=499122177;
    cny2[0]=1;
    fo(i,1,n*n) cny2[i]=cny2[i-1]*ny2%mo;
    fo(i,1,n)
    {
        ans=(ans+g[i]*cny2[i*(n-i)]%mo)%mo;
    }
    printf("%lld\n",ans*cf%mo);
}

猜你喜欢

转载自blog.csdn.net/hzj1054689699/article/details/80024795