AC 我开了__int128 复杂度是O(输入)
查看原帖
AC 我开了__int128 复杂度是O(输入)
208511
david2du楼主2021/11/14 16:21
  • 每个点反向寻找,从他的所有父节点将污水分一些出来
    • 如果父节点没有计算过,再向上寻找其父节点···
    • 如果父节点计算过,累加到自己
  • 因为约等于每个点只会算一次, 核心代码复杂度是O(fa * n)
  • 分数可以用pair<>代替
  • 分数累加的时候,通分相加,long long 会溢出,所以要用高精度或者__int128
#include <bits/stdc++.h>
using namespace std;

typedef __int128 ll;

typedef pair<ll, ll> P;

ll n, m;

vector<ll> fa[100010];
ll chdN[100010]; // children Number
bitset<100010> nok; // not ok
vector<ll> out; // 输出节点编号

P water[100010];

inline void add(P &A, const P &B)
{
	A.first = (A.first * B.second + B.first * A.second);
	A.second *= B.second;
	
	ll g = __gcd(A.first, A.second);
	A.first /= g;
	A.second /= g;
}

inline P div(P A, ll B)
{
	A.second *= B;
	
	ll g = __gcd(A.first, A.second);
	A.first /= g;
	A.second /= g;
	
	return A;
}

inline void dfs(ll now)
{
	for (ll i = 0; i < fa[now].size(); i++)
	{
		if (nok[fa[now][i]])
		{
			dfs(fa[now][i]);
		}
		add(water[now], div(water[fa[now][i]], chdN[fa[now][i]]));
	}
	nok[now] = false;
}

inline ll read()
{
	ll x = 0, f = 1;
	
	char ch = getchar();
	while(ch < '0' || ch > '9')
	{
		if(ch == '-')
		{
			f = -1;
		}
		ch = getchar();
	}
	
	while(ch >= '0' && ch <= '9')
	{
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

inline void write(__int128 x)
{
	if(x < 0)
	{
		putchar('-');
		x = -x;
	}
	
	if(x > 9)
	{
		write(x / 10);
	}
	
	putchar(x % 10 + '0');
}

int main(int argc, char const *argv[])
{
	n = read();
	m = read();
	
	for (ll i = 1; i <= n; i++)
	{
		chdN[i] = read();
		
		if (chdN[i] == 0)
		{
			out.push_back(i);
			continue;
		}
		
		for (ll j = 0; j < chdN[i]; j++)
		{
			ll v = 0;
			
			v = read();
			
			fa[v].push_back(i); // 只存了father
			nok[v] = true;
		}
	}
	
	for (ll i = 1; i <= m; i++)
	{
		nok[i] = false;
		water[i] = make_pair(1LL, 1LL);
	}
	for (ll i = m + 1; i <= n; i++)
	{
		water[i].second = 1;
	}
	
	for (ll i = (m + 1); i <= n; i++)
	{
		if (nok[i])
		{
			dfs(i);

		}
		
	}
	
	for (ll i = 0; i < out.size(); i++)
	{
		ll g = __gcd(water[out[i]].first, water[out[i]].second);

		
		write(water[out[i]].first / g);
		cout << " ";
		write(water[out[i]].second / g);
		cout << endl;

	}

	return 0;
}
2021/11/14 16:21
加载中...