BZOJ 4602

有一个齿轮系统,共n个齿轮,有m个关系,每一个形如“a齿轮转x圈,则b齿轮转y圈”,问这个系统是否合法,多组询问。

$$T \leq 32, 1 \leq n \leq 1000,1 \leq m \leq 10000, 1 \leq |x|,|y| \leq 100$$

显然这个转动关系具有传递性,因此可以用带权并查集维护,但这个转动圈数化成整数后太大了,所以要把数化成唯一分解式。

const int MAXN = 1000 + 5, MAXK = 100 + 5, MAXP = 30 + 5;

struct Input {
  char buf[1 << 25], *s;
  
  Input() {
#ifdef LOCAL
    freopen("BZOJ4602.in", "r", stdin);
    freopen("BZOJ4602.ans", "w", stdout);
#endif
    fread(s = buf, 1, 1 << 25, stdin);
  }
  
  friend Input &operator>>(Input &io, int &x) {
    x = 0;
    int p = 1;
    while (!isdigit(*io.s)) {
      if (*io.s == '-')
        p = -1;
      ++ io.s;
    }
    while (isdigit(*io.s))
      x = x * 10 + *io.s ++ - '0';
    x *= p;
    return io;
  }
} cin;

int pri[MAXP], p_cnt;
bool np[MAXK];

IL void Init(int n) {
  np[1] = 1;
  For(i, 2, n) {
    if (!np[i])
      pri[++ p_cnt] = i;
    for (int j = 1; j <= p_cnt && i * pri[j] <= n; ++ j) {
      np[i * pri[j]] = 1;
      if (!(i % pri[j]))
        break;
    }
  }
}

struct Integer {
  bool is_neg;
  int factor[MAXP];
  
  Integer() {
    is_neg = 0;
    memset(factor, 0, sizeof factor);
  }
  
  Integer(int x) {
    is_neg = 0;
    if (x < 0)
      is_neg = 1, x = -x;
    memset(factor, 0, sizeof factor);
    For(i, 1, p_cnt)
      while (!(x % pri[i]))
        x /= pri[i], ++ factor[i];
  }
  
  friend Integer operator*(const Integer &a, const Integer &b) {
    Integer result;
    result.is_neg = a.is_neg ^ b.is_neg;
    For(i, 1, p_cnt)
      result.factor[i] = a.factor[i] + b.factor[i];
    return result;
  }
  
  friend Integer operator/(const Integer &a, const Integer &b) {
    Integer result;
    result.is_neg = a.is_neg ^ b.is_neg;
    For(i, 1, p_cnt)
      result.factor[i] = a.factor[i] - b.factor[i];
    return result;
  }
  
  friend bool operator==(const Integer &a, const Integer &b) {
    if (a.is_neg != b.is_neg)
      return 0;
    For(i, 1, p_cnt)
      if (a.factor[i] != b.factor[i])
        return 0;
    return 1;
  }
  
  friend bool operator!=(const Integer &a, const Integer &b) {
    return !(a == b);
  }
};

struct DSU {
  int fa[MAXN];
  Integer dist[MAXN];
  
  void init(int n) {
    For(i, 1, n)
      fa[i] = i, dist[i] = Integer();
  }
  
  int find(int x) {
    if (fa[x] != x) {
      int par = find(fa[x]);
      dist[x] = dist[x] * dist[fa[x]];
      return fa[x] = par;
    } else
      return x;
  }
  
  bool same(int x, int y) {
    return find(x) == find(y);
  }
  
  bool merge(int x, int y, const Integer &ratio) {
    if (same(x, y)) {
      Integer tmp = dist[y] / dist[x];
      if (ratio != tmp)
        return 0;
    } else
      dist[fa[y]] = ratio * dist[x] / dist[y], fa[fa[y]] = fa[x];
    return 1;
  }
} U;

int main() {
  Init(100);
  int T;
  cin >> T;
  For(i, 1, T) {
    int n, m;
    cin >> n >> m;
    U.init(n);
    bool ok = 1;
    For(i, 1, m) {
      int u, v, x, y;
      cin >> u >> v >> x >> y;
      Integer a(x), b(y);
      if (!ok)
        continue;
      if (!U.merge(u, v, b / a))
        ok = 0;
    }
    printf("Case #%d: %s\n", i, ok ? "Yes" : "No");
  }
  return 0;
}

 

posted @ 2018-10-14 18:02  sjkmost  阅读(144)  评论(0编辑  收藏  举报