zoukankan      html  css  js  c++  java
  • 「CTS2019 | CTSC2019」氪金手游 解题报告

    「CTS2019 | CTSC2019」氪金手游

    降 智 好 题 ...

    考场上签到失败了,没想容斥就只打了20分暴力...


    考虑一个事情,你抽中一个度为0的点,相当于把这个点删掉了(当然你也只能抽中度为0的点)

    删掉就是字面意思,就是剩下的树变成子问题

    考虑为什么,在抽中这个(i)号点后,抽中其他点的概率为

    [frac{W-w_i}{W}sum_{i=0}^{infty}(frac{w_i}{W})^i=1 ]

    说明这个点已经白给了


    然后考虑这个树如果是一颗外向树,就是每个点先父亲再自己

    有个比较显然的dp,令(dp_{i,j})表示子树(i)(sum w=j)时的概率,转移的时候合并一下子树就好了


    然后考虑到,树上一条边相当于一个限制,如果我们去掉这个限制,会多统计一些东西,但是也可以发现,这个多统计的东西就是把边反向的答案...

    还是令(dp_{i,j})代表刚刚那个

    如果边正向就正常转移

    如果反向,就加上去掉限制的再减掉反向的答案(注意到去掉限制的是独立的,我们不需要改变(W),只是给他合并一下)


    Code:

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    using std::min;
    const int SIZE=1<<21;
    char ibuf[SIZE],*iS,*iT;
    //#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),iS==iT?EOF:*iS++):*iS++)
    #define gc() getchar()
    template <class T>
    void read(T &x)
    {
    	x=0;char c=gc();
    	while(!isdigit(c)) c=gc();
    	while(isdigit(c)) x=x*10+c-'0',c=gc();
    }
    const int mod=998244353;
    int inline add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    #define mul(x,y) (1ll*(x)*(y)%mod)
    int qp(int d,int k){int f=1;while(k){if(k&1)f=mul(f,d);d=mul(d,d),k>>=1;}return f;}
    const int N=1e3+10;
    int n,p[N][4],dp[N][N*3],tmp[N*3],siz[N],inv[N*3];
    int head[N],to[N<<1],Next[N<<1],type[N<<1],cnt;
    void addedge(int u,int v)
    {
    	to[++cnt]=v,type[cnt]=1,Next[cnt]=head[u],head[u]=cnt;
    	to[++cnt]=u,type[cnt]=0,Next[cnt]=head[v],head[v]=cnt;
    }
    void dfs(int now,int fa)
    {
    	dp[now][0]=1;
    	for(int v,i=head[now];i;i=Next[i])
    		if((v=to[i])!=fa)
    		{
    			dfs(v,now);
    			memset(tmp,0,sizeof tmp);
    			for(int j=0;j<=siz[now];j++)
    				for(int k=0;k<=siz[v];k++)
    				{
    					int aya=mul(dp[now][j],dp[v][k]);
    					if(type[i])
    						tmp[j+k]=add(tmp[j+k],aya);
    					else
    					{
    						tmp[j+k]=add(tmp[j+k],mod-aya);
    						tmp[j]=add(tmp[j],aya);
    					}
    				}
    			siz[now]+=siz[v];
    			for(int j=0;j<=siz[now];j++) dp[now][j]=tmp[j];
    		}
    	memset(tmp,0,sizeof tmp);
    	for(int i=0;i<=siz[now];i++)
    		for(int j=1;j<=3;j++)
    			tmp[i+j]=add(tmp[i+j],mul(dp[now][i],mul(p[now][j],mul(j,inv[i+j]))));
    	siz[now]+=3;
    	for(int i=0;i<=siz[now];i++)
    		dp[now][i]=tmp[i];
    }
    int main()
    {
    	read(n);
    	for(int a1,a2,a3,i=1;i<=n;i++)
    	{
    		read(a1),read(a2),read(a3);
    		int sum=qp(a1+a2+a3,mod-2);
    		p[i][1]=mul(a1,sum);
    		p[i][2]=mul(a2,sum);
    		p[i][3]=mul(a3,sum);
    	}
    	inv[0]=1;
    	for(int i=1;i<=n*3;i++) inv[i]=qp(i,mod-2);
    	for(int u,v,i=1;i<n;i++)
    	{
    		read(u),read(v);
    		addedge(u,v);
    	}
    	dfs(1,0); 
    	int ans=0;
    	for(int i=0;i<=3*n;i++) ans=add(ans,dp[1][i]);
    	printf("%d
    ",ans);
    	return 0;
    }
    

    2019.5.20

  • 相关阅读:
    hdu 5387 Clock (模拟)
    CodeForces 300B Coach (并查集)
    hdu 3342 Legal or Not(拓扑排序)
    hdu 3853 LOOPS(概率DP)
    hdu 3076 ssworld VS DDD(概率dp)
    csu 1120 病毒(LICS 最长公共上升子序列)
    csu 1110 RMQ with Shifts (线段树单点更新)
    poj 1458 Common Subsequence(最大公共子序列)
    poj 2456 Aggressive cows (二分)
    HDU 1869 六度分离(floyd)
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10896058.html
Copyright © 2011-2022 走看看