先枚举 1∼m 的每个节点,如果没被标记就 bfs 一次,bfs 的同时标记经过的每个节点,然后计算分数。每个节点排水排完之后都会清空
60pts,只通过了 m=1 的情况,剩下的都是 WA,代码:
//solve all tests
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
#define int long long
const int N = 100010;
int n, m;
vector<int> v[N];
int d[N], dat1[N], dat2[N];
bool vis[N];
queue<int> q;
int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') { f = (ch == '-' ? -1 : f); ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
int __gcd(int a, int b) {
return b ? __gcd(b, a % b) : a;
}
int __lcm(int a, int b) {
int gcd = __gcd(a, b);
return a * b / gcd;
}
pair<int, int> make(int a, int b, int x, int y, int len) {
int val1 = x, val2 = len * y;
int gcd1 = __gcd(val1, val2);
val1 /= gcd1, val2 /= gcd1;
int mo = b * val2;
int son = a * val2 + b * val1;
int gcd = __gcd(mo, son);
return make_pair(son / gcd, mo / gcd);
}
void bfs(int x) {
q.push(x); vis[x] = true;
while (q.size()) {
int l = q.front(); q.pop();
int len = v[l].size();
if (!len) continue;
for (int i = 0; i < len; i++) {
int son = v[l][i]; vis[son] = true;
// int lcm = __lcm(dat2[l], dat2[son]);
// int x = lcm / dat2[l], y = lcm / dat2[son];
// int val1 = dat1[son] * y + dat1[son] * x, val2 = lcm;
// int val1 = dat1[son] + len * dat1[l], val2 =
// int gcd = __gcd(val1, val2);
// dat1[son] = val1 / gcd, dat2[son] = val2 / gcd;
pair<int, int> p = make(dat1[son], dat2[son], dat1[l], dat2[l], len);
dat1[son] = p.first, dat2[son] = p.second;
q.push(son);
}
dat1[l] = 0, dat2[l] = 1;
}
}
signed main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> d[i];
for (int j = 1; j <= d[i]; j++) {
int x; cin >> x;
v[i].push_back(x);
}
if (i <= m) dat1[i] = 1;
dat2[i] = 1;
}
// for (int i = 1; i <= m; i++) dat1[i] = dat2[i] = 1;
bfs(1);
for (int i = 1; i <= m; i++)
if (!vis[i]) bfs(i);
for (int i = 1; i <= n; i++) {
if (d[i]) continue;
cout << dat1[i] << " " << dat2[i] << "\n";
}
return 0;
}