A. Minimal Coprime
题意:互素区间是指\(gcd(l, r) = 1\)的区间,极小互素区间是互素区间并且没有一个被他包含的区间也是互素区间。问你区间\([l, r]\)里有多少个极小互素区间。
根据数论的基础知识,\(x,x+1\)一定是互素的,所以统计所有长度为\(2\)的区间就行,不过要注意,\([1, 1]\)是唯一一个长度不为\(2\)的极小互素区间。
点击查看代码
void solve() {int l, r;std::cin >> l >> r;int ans = r - l;if (l == 1) {ans = std::max(ans, 1);}std::cout << ans << "\n";
}
B. Subsequence Update
题意:给你一个数组,你可以翻转一个子序列,求一次操作后\([l, r]\)区间的最小总和。
赛时把子序列看成子数组了。。。
左边的最小的\(r-l+1\)个数一定能翻转到\([l, r]\)里。具体操作是,假设前\(r-l+1\)小的数有\(x\)个不在\([l, r]\)里面,那么\([l, r]\)里有\((r-l+1)-x\)个最小值,发现不是最小值的正好也是\((r-l+1-(r-l+1)-x)=x\)个,那么明显可以选中这些数进行翻转,这样\(x\)个数就到\([l, r]\)里了。右边同理,所以两边模拟一下取最小就行。
点击查看代码
void solve() {int n, l, r;std::cin >> n >> l >> r;std::vector<int> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}auto b = a;std::sort(a.begin(), a.begin() + r);i64 sum1 = 0, sum2 = 0;for (int i = 0; i < r - l + 1; ++ i) {sum1 += a[i];}std::sort(b.begin() + l - 1, b.end());for (int i = l - 1; i < l - 1 + r - l + 1; ++ i) {sum2 += b[i];}i64 ans = std::min(sum1, sum2);std::cout << ans << "\n";
}
C. Remove Exactly Two
题意:给你一颗树,你要删掉两个点,然后使得剩下的连通块最大。
设\(u\)的度数为\(deg_u\)。因为树没有环,那么如果删一个点就会分成\(deg_u\)块,那就是删度数最大的。现在考虑两个点,发现如果删除的两个点之间没有连边的话是不影响的,如果连边则因为有一条边重复了会少分成一个块。所以我们先枚举所有度数最大的点看有没有两个最大点之间没有连边,有点话就选这两个点就行。否则就拿一个度数最大的和一个剩下点度数最大的点就行。然后我是用并查集数的联通块,不过好像可以直接算。
这题赛时代码写的奇丑。
点击查看代码
struct DSU {std::vector<int> f, siz;DSU() {}DSU(int n) {init(n);}void init(int n) {f.resize(n);std::iota(f.begin(), f.end(), 0);siz.assign(n, 1);}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;return true;}int size(int x) {return siz[find(x)];}
};void solve() {int n;std::cin >> n;std::vector<std::vector<int> > adj(n);std::vector<std::pair<int, int> > edges;std::vector<int> deg(n);for (int i = 1; i < n; ++ i) {int u, v;std::cin >> u >> v;-- u, -- v;adj[u].push_back(v);adj[v].push_back(u);++ deg[u]; ++ deg[v];edges.push_back({u, v});}if (n == 2) {std::cout << 0 << "\n";return;}int max = *std::max_element(deg.begin(), deg.end());std::vector<int> b;int x = -1, y = -1, mx = 0;for (int i = 0; i < n; ++ i) {if (deg[i] == max) {b.push_back(i);}}if (b.size() >= 2) {int mx = 0;for (auto & u : b) {for (auto & v : b) {if (u != v) {int flag = 0;for (auto & x : adj[u]) {if (x == v) {flag = 1;break;}}if (max * 2 - flag > mx) {mx = max * 2 - flag;x = u, y = v;}}}if (mx == 2 * max) {break;}}} else {x = b[0];int mx = -1;for (int i = 0; i < n; ++ i) {if (i == x) {continue;}int flag = 0;for (auto & j : adj[i]) {if (x == j) {flag = 1;break;}}if (max + deg[i] - flag > mx) {mx = max + deg[i] - flag;y = i;}}}DSU d(n);for (auto & [u, v] : edges) {if (u != x && u != y && v != x && v != y) {d.merge(u, v);}}int ans = 0;for (int i = 0; i < n; ++ i) {if (i != x && i != y && d.find(i) == i) {++ ans;}}std::cout << ans << "\n";
}
D. Game With Triangles
待补