zoukankan      html  css  js  c++  java
  • 并不对劲的loj3124:uoj477:p5405:[CTS2019]氪金手游

    题目大意

    有一个有向图,这个有向图的生成方式是把一棵(n)个点的树的每条无向边重新定向。
    每个点(i)的点权有(p_{i,1})的概率为1,有(p_{i,2})的概率为2,有(p_{i,3})的概率为3。
    取无限次点,每次取某个点的概率=(该点点权)/(总点权和)。
    问:对于每条边,都满足起点第一次被取出来的时间比终点第一次被取出来的时间早的概率模998244353。
    (nleq 1000)

    题解

    当所有边在树中都是父亲指向且所有点的权值都确定时,设(f(i))表示点(i)和它的子树符合条件的概率。
    考虑子树向父亲的转移:当一个点的子树都符合条件时,该点及子树都符合条件当且仅当该点第一次取在子树中所有点第一次取之前,这件事发生的概率是(frac{该点点权}{该点及子树中所有点的点权和})
    点权不确定时,设(f(i,j))表示点(i)的子树和点(i)的点权和为(j)时,点(i)和它的子树符合条件的概率。树上背包转移。
    有反向边时:所有反向边都符合的概率=所有反向边符合或不符合都行的概率-存在反向边不符合的概率。
    反向边不符合相当于把反向边当成正向边算。
    算这个需要容斥,把反向边当正向边算时,转移时乘容斥系数。

    代码
    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<queue>
    #include<set>
    #include<stack>
    #include<vector>
    #define rep(i,x,y) for(register int i=(x);i<=(y);++i)
    #define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
    #define view(u,k) for(int k=fir[u];~k;k=nxt[k])
    #define maxn 1007
    #define maxsiz 3007
    #define LL long long
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)&&ch!='-')ch=getchar();
    	if(ch=='-')f=-1,ch=getchar();
    	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    	return x*f;
    }
    void write(int x)
    {
    	if(x==0){putchar('0'),putchar('
    ');return;}
    	int f=0;char ch[20];
    	if(x<0)putchar('-'),x=-x;
    	while(x)ch[++f]=x%10+'0',x/=10;
    	while(f)putchar(ch[f--]);
    	putchar('
    ');
    	return;
    }
    const int mod=998244353;
    int n,dp[maxn][maxsiz],siz[maxn],fir[maxn],v[maxn<<1],nxt[maxn<<1],cnte,p[maxn][4],ans,tmp[maxsiz],inv[maxsiz];
    int getd(int k){return k<(k^1)?1:0;}
    void ade(int u1,int v1){v[cnte]=v1,nxt[cnte]=fir[u1],fir[u1]=cnte++;}
    int mo(int x){if(x<0)return x+mod;return x>=mod?x-mod:x;}
    int mul(int x,int y){int res=1;while(y){if(y&1)res=(LL)res*x%mod;x=(LL)x*x%mod,y>>=1;}return res;}
    void getdp(int u,int fa)
    {
    	rep(i,1,3)dp[u][i]=(LL)i*p[u][i]%mod;siz[u]=1;
    	view(u,k)if(v[k]!=fa)
    	{
    		getdp(v[k],u);
    		if(getd(k))
    		{
    			int li1=siz[u]*3,li2=siz[v[k]]*3;
    			rep(i,1,li1+li2)tmp[i]=0;
    			rep(i,1,li1)rep(j,1,li2)
    			{
    				tmp[i+j]=mo(tmp[i+j]+(LL)dp[u][i]*dp[v[k]][j]%mod);
    			}
    		}
    		else
    		{
    			int li1=siz[u]*3,li2=siz[v[k]]*3;
    			rep(i,1,li1+li2)tmp[i]=0;
    			rep(i,1,li1)rep(j,1,li2)tmp[i+j]=mo(tmp[i+j]+(LL)dp[u][i]*mo(-dp[v[k]][j])%mod);
    			rep(i,1,li1)rep(j,1,li2)tmp[i]=mo(tmp[i]+(LL)dp[u][i]*dp[v[k]][j]%mod);
    		}
    		siz[u]+=siz[v[k]];int li=siz[u]*3;
    		rep(i,1,li)dp[u][i]=tmp[i];
    	}
    	int li=siz[u]*3;
    	rep(i,1,li)dp[u][i]=(LL)dp[u][i]*inv[i]%mod;
    }
    int main()
    {
    	n=read();int li=n+n+n;
    	rep(i,1,li)inv[i]=mul(i,mod-2);
    	rep(i,1,n)
    	{
    		p[i][1]=read(),p[i][2]=read(),p[i][3]=read(),fir[i]=-1;
    		int invp=mo(p[i][1]+mo(p[i][2]+p[i][3]));invp=mul(invp,mod-2);
    		p[i][1]=(LL)p[i][1]*invp%mod,p[i][2]=(LL)p[i][2]*invp%mod,p[i][3]=(LL)p[i][3]*invp%mod;
    	}
    	rep(i,2,n){int x=read(),y=read();ade(x,y),ade(y,x);}
    	getdp(1,0);li=siz[1]*3;rep(i,0,li)ans=mo(ans+dp[1][i]);
    	write(ans);
    	return 0;
    }
    
  • 相关阅读:
    commonjs promise/A 规范
    Java之抽象类
    Java中多态的用法
    Java之方法的重写
    Java中static的用法
    java中this的用法
    Java概述
    二叉排序树的创建、插入、删除
    常用排序算法
    LeetCode小白菜笔记[2]:Reverse Integer
  • 原文地址:https://www.cnblogs.com/xzyf/p/13143879.html
Copyright © 2011-2022 走看看