Connect the Dots§
思路很简单,仔细阅读题目可以发现
d的数据范围很小。可以考虑
DP + DSU。设计
DP状态,f[a][d]表示位置a最多和右侧多少个位置(d为间距)相连。转移的时候判断旧的状态能不能和当前位置建边,动态
merge即可。我的评价是十分
easy。#ifndef CAIKI_LOCAL #include <bits/stdc++.h> #endif #ifdef CAIKI_LOCAL #include <algorithm> #include <iostream> #include <numeric> #include <vector> auto _ = []() { freopen("../io/in.txt", "r", stdin); freopen("../io/out.txt", "w", stdout); return true; }(); #endif #define int long long struct DSU { std::vector<int> f, siz; int cnt; DSU() {} DSU(int n) { init(n); } void init(int n) { f.resize(n); std::iota(f.begin(), f.end(), 0); siz.assign(n, 1); cnt = n; } int find(int x) { while (x != f[x]) { x = f[x] = f[f[x]]; } return x; } bool same(int x, int y) { return find(x) == find(y); } bool merge(int x, int y) { x = find(x); y = find(y); if (x == y) { return false; } siz[x] += siz[y]; f[y] = x; cnt--; return true; } int size(int x) { return siz[find(x)]; } }; void solve() { int n, m; std::cin >> n >> m; std::vector<std::vector<int>> f(n + 1, std::vector<int>(11, 0)); DSU dsu(n + 1); while (m--) { int a, d, k; std::cin >> a >> d >> k; f[a][d] = std::max(f[a][d], k); } for (int i = 1; i <= n; i++) { for (int d = 1; d <= 10; d++) { int j = i - d; if (j < 1) { continue; } if (f[j][d]) { dsu.merge(i, j); } f[i][d] = std::max(f[i][d], f[j][d] - 1); } } std::cout << dsu.cnt - 1 << '\n'; } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int t; std::cin >> t; while (t--) { solve(); } return 0; }