• 2020年HDU多校第六场 1010 Expectation(矩阵树)


    2020年HDU多校第六场 1010 Expectation(矩阵树)

    题意:给一个图,输出其随机生成树的权值的期望,其权值为树的所有边的与。

    题解:要写这个题,需要知道一个知识点,矩阵树定理,它可以求出一个图内生成树的数量,放个板子。

    #include<iostream>
    using namespace std;
    const int mod=1e9+7;
    int n;
    int f[207][207];
    //f[i][i] 存i点的度数
    //f[i][j] 存i点到j点的边数的相反数
    //ans为图的生成树数量
    ll gauss () {
        ll ans = 1 ;
        for (int i = 1; i <= n; i ++) {
            for (int j = i + 1; j <= n; j ++) {
                while (f[j][i]) {
                    ll t = f[i][i] / f[j][i] ;
                    for (int k = i; k < tot; k ++)
                        f[i][k] = (f[i][k] - t * f[j][k] + mod) % mod ;
                    swap (f[i], f[j]) ;
                    ans = -ans ;
                }
            }
            ans = (ans * f[i][i]) % mod ;
        }
        return (ans + mod) % mod ;
    }
    
    

    然后,我们可以先求出生成树的总数,毕竟要求期望要除总数,然后算分子部分,由题意我们要求的是所有边的按位与,所以:

    第一,我们将31位数分开算贡献,每位之间的答案互不影响;

    第二,若要某位产生贡献,必然要其生成树的所有边都要有那一位,所以没有那一位的边不加入图。

    意思就是枚举每一位,每次都重新建一次图用矩阵数定理算一次答案。

    #include<iostream>
    #include<cstring>
    using namespace std;
    #define ll long long
    const ll mod=998244353;
    ll n,m,t,sum;
    ll f[207][207];
    ll u[40007],v[40007],w[40007];
    ll gauss () {
        ll ans = 1 ;
        for (int i = 1; i < n; i ++) {
            for (int j = i + 1; j < n; j ++) {
                while (f[j][i]) {
                    ll t = f[i][i] / f[j][i] ;
                    for (int k = i; k < n; k ++)
                        f[i][k] = (f[i][k] - t * f[j][k] + mod) % mod ;
                    swap (f[i], f[j]) ;
                    ans = -ans ;
                }
            }
            ans = (ans * f[i][i]) % mod ;
        }
        return (ans + mod) % mod ;
    }
    long long int pow(long long int x,long long int n,long long int mod)
    {
        long long int res=1;
    	while(n>0)
    	{
    	   if(n%2==1)
    	   {
    	   	 res=res*x;
    	   	 res=res%mod;
    	   }
    	   x=x*x;
    	   x=x%mod;
    	   n>>=1;
    	}
    	return res;
    }
    void add(int u,int v){
    	f[u][u]++;f[v][v]++;
    	f[u][v]--;f[v][u]--;
    }
    void init(){
    	memset(f,0,sizeof(f));
    }
    int main(){
    	scanf("%lld",&t);
    	while(t--){
    		init();
    		scanf("%lld%lld",&n,&m);
    		for(int i=1;i<=m;i++){
    			cin>>u[i]>>v[i]>>w[i];
    			add(u[i],v[i]);
    		}
    		sum=gauss();
    		sum=pow(sum,mod-2,mod);
    		ll aqours=0,er=1;
    		for(int i=0;i<=30;i++){
    			init();
    			for(int i=1;i<=m;i++){
    				if(w[i]&er){
    					add(u[i],v[i]);
    				}
    			}
    			aqours=(aqours+gauss()*er%mod*sum%mod)%mod;
    			er*=2;
    		}
    		printf("%lld
    ",aqours);
    	}
    }
    
    
  • 相关阅读:
    01_Linux基础篇
    Docker
    Day02_IP地址详解&进制转换&DOS基本命令与批处理
    Day01_虚拟化架构与系统部署
    重学TCP/IP协议和三次握手四次挥手
    作为一个程序员,CPU的这些硬核知识你必须会!
    通过docker-compose制作dubbo-admin和zookeeper组合服务
    双主master-master复制Err 1677故障分析
    唐宇迪-人工智能学习路线(上篇)
    DNS访问原理只需9个步骤
  • 原文地址:https://www.cnblogs.com/whitelily/p/13449623.html
Copyright © 2020-2023  润新知