CF802L Send the Fool Further! (hard) 树上高斯消元

朴素的高斯消元是 $O(n^3)$ 的,但是由于叶节点是终止节点,所以可以逐层向上推成 $k\times f(fa)+b$ 的形式.

推到根节点时直接取根节点的 $b$ 值就可以了.

code:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define mod 1000000007
#define N 100067
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int qpow(int x,int y)
{
	int tmp=1;
	for(;y;y>>=1,x=(ll)x*x%mod)
		if(y&1)
			tmp=(ll)tmp*x%mod;
	return tmp;
}
int n,edges;
int deg[N],hd[N],to[N<<1],nex[N<<1],val[N<<1],k[N],b[N];
void add(int u,int v,int c)
{
	nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c;
}
void dfs(int x,int ff,int pr)
{
	// deg[x]=1;
	for(int i=hd[x];i;i=nex[i]) if(to[i]!=ff) dfs(to[i],x,val[i]); // ,++deg[x];
	if(deg[x]==1)  k[x]=0,b[x]=0;
	else
	{
		int len=0;
		int bb=0;
		int kk=0;
		for(int i=hd[x];i;i=nex[i])  if(to[i]!=ff)  (kk+=k[to[i]])%=mod;
		for(int i=hd[x];i;i=nex[i])  len+=val[i];
		for(int i=hd[x];i;i=nex[i])  if(to[i]!=ff)  (bb+=b[to[i]])%=mod;
		int t=(ll)qpow((deg[x]-kk+mod)%mod,mod-2);
		b[x]=(ll)(bb+len)*t%mod;
		k[x]=t;
	}
}
int main()
{
	// setIO("input");
	scanf("%d",&n);
	int i,j;
	for(i=1;i<n;++i)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z),++x,++y;
		++deg[x],++deg[y];
		add(x,y,z),add(y,x,z);
	}
	dfs(1,0,0);
	printf("%d\n",(ll)b[1]%mod);
	return 0;
}

  

原文地址:https://www.cnblogs.com/guangheli/p/12399128.html

时间: 2024-11-10 01:25:08

CF802L Send the Fool Further! (hard) 树上高斯消元的相关文章

bzoj 2784 [JLOI2012]时间流逝——树上高斯消元

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2784 一个状态可以加很多个能量圈,但减少能量圈的情况只有一种.所以可以用树来刻画. 然后就变成树上高斯消元的套路了.注意根节点的 P 等于 0 . 发现不是要求 dp[ 1 ] 就必须在那个式子里设出 a*dp[ 1 ] 之类的. 据说树上的点大概有 1.2*106 个.大概就是贝尔数吧. #include<cstdio> #include<cstring> #include

bzoj 2784 时间流逝 —— 树上高斯消元

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2784 其实转移是一棵树,从根到一个点表示一种能量圈状态,当能量值大于 T 是停止,也就是成为叶子: 点数大约是整数划分,据说是 1.2e6 左右,可以 dfs: 设 \( d[x] \) 是儿子数,则 \( f[x] = p*(f[fa]+1) + (1-p) \frac{\sum\limits_{v \in son}(f[v]+1)}{d[x]} \) 仍然设 \( f[x] = K[x

【CF802L】Send the Fool Further! (hard) 高斯消元

[CF802L]Send the Fool Further! (hard) 题意:给你一棵n个节点的树,每条边有长度,从1号点开始,每次随机选择一个相邻的点走,走到一个叶子时就停止,问期望走的总路程. $n\le 10^5$ 题解:很自然想到游走那题,于是想到高斯消元,但是正常高斯消元是$O(n^3)$的.不过我们有一个套路:在树上进行高斯消元的复杂度是$O(n)$的. 先列出方程:设f(x)表示从x开始期望还要走的路程,x的度数是d,那么$f(x)=\frac {f(fa)+len} d+\f

BZOJ 2466 中山市选2009 树 高斯消元+暴力

题目大意:树上拉灯游戏 高斯消元解异或方程组,对于全部的自由元暴力2^n枚举状态,代入计算 这做法真是一点也不优雅... #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 110 using namespace std; int n,m; int f[M][M],is_free[M],tot; int ans[M],cnt; void

【弱校胡策】2016.4.14 (bzoj2164)最短路+状压DP+矩阵乘法+高斯消元+树链剖分+线段树+背包DP

cyyz&qhyz&lwyz&gryz弱校胡策 命题人:cyyz ws_fqk T3暴力写挫了 50+10+0滚粗辣! 奇妙的约会(appointment.cpp/c/pas) [问题描述] DQS和sxb在网上结识后成为了非常好的朋友,并且都有着惊人 的OI水平.在NOI2333的比赛中,两人均拿到了金牌,并保送进入 HU/PKU.于是两人决定在这喜大普奔的时刻进行面基. NOI2333参赛选手众多,所以安排了n个考点,DQS在1号考点, 而sxb在n号考点.由于是举办全国性赛事

poj_1222_高斯消元

第一次学习使用高斯消元,将灯板化为线性方程组,进行求解. /*######################################################################### # File Name: poj_1222.cpp # Author: CaoLei # Created Time: 2015/7/20 15:48:04 ###################################################################

HDU 4870 Rating(高斯消元)

HDU 4870 Rating 题目链接 题意:一个人注册两个账号,初始rating都是0,他每次拿低分的那个号去打比赛,赢了加50分,输了扣100分,胜率为p,他会打到直到一个号有1000分为止,问比赛场次的期望 思路:f(i, j)表示i >= j,第一个号i分,第二个号j分时候,达到目标的期望,那么可以列出转移为f(i, j) = p f(i', j') + (1 - p) f(i'' + j'') + 1 f(i', j')对应的是赢了加分的状态,f(i'', j'')对应输的扣分的状态

【BZOJ 4171】 4171: Rhl的游戏 (高斯消元)

4171: Rhl的游戏 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 74  Solved: 33[Submit][Status][Discuss] Description RHL最近迷上一个小游戏:Flip it.游戏的规则很简单,在一个N*M的格子上,有一些格子是黑色,有一些是白色 .每选择一个格子按一次,格子以及周围边相邻的格子都会翻转颜色(边相邻指至少与该格子有一条公共边的格子 ),黑变白,白变黑.RHL希望把所有格子都变成白色的.不幸

POJ 1830 开关问题 高斯消元,自由变量个数

http://poj.org/problem?id=1830 如果开关s1操作一次,则会有s1(记住自己也会变).和s1连接的开关都会做一次操作. 那么设矩阵a[i][j]表示按下了开关j,开关i会被操作一次,记得a[i][i] = 1是必须的,因为开关i操作一次,本身肯定会变化一次. 所以有n个开关,就有n条方程, 每个开关的操作次数总和是:a[i][1] + a[i][2] + ... + a[i][n] 那么sum % 2就代表它的状态,需要和(en[i] - be[i] + 2) % 2