好久没有div3场了,就去水了一场,队友先看了D,我看了C,队友AC了D题告诉我说简单题,然后我就跳了ABD这三题
C. Sequence Transformation
大致题意
给你一个数列,让你选择一个数列中已经存在的值 x x x,然后重复进行一个操作:每次选择一个不含有 x x x的区间并将其删除,请问最少需要多少次操作
分析
由于 x x x是自己定的,所以简单来说就是找出一个 x x x,将数列中的 x x x移去后,数列断开的地方最少
简单的暴力题,无非是怎么样实现好看一点
AC code
#include <bits/stdc++.h>
using namespace std;
void solve() {
int _;
cin >> _;
for (int ts = 0; ts < _; ++ts) {
int n;
cin >> n;
vector<vector<int>> data(n + 1);
for (int i = 0; i < n; ++i) {
int tmp;
cin >> tmp;
data[tmp].push_back(i);
}
int ans = INT_MAX;
for (int i = 0; i <= n; ++i) {
if (data[i].empty()) continue;
int tmp = 2;
for (int j = 1; j < data[i].size(); ++j) if (data[i][j] - data[i][j - 1] != 1) tmp++;
if (data[i][0] == 0) tmp--;
if (data[i].back() == n - 1) tmp--;
ans = min(ans, tmp);
}
cout << ans << endl;
}
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
#ifdef ACM_LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
signed localTestCount = 1, localReadPos = cin.tellg();
char localTryReadChar;
do {
if (localTestCount > 20)
throw runtime_error("Check the stdin!!!");
auto startClockForDebug = clock();
solve();
auto endClockForDebug = clock();
cout << "Test " << localTestCount << " successful" << endl;
cerr << "Test " << localTestCount++ << " Run Time: "
<< double(endClockForDebug - startClockForDebug) / CLOCKS_PER_SEC << "s" << endl;
cout << "--------------------------------------------------" << endl;
} while (localReadPos != cin.tellg() && cin >> localTryReadChar && localTryReadChar != '$' &&
cin.putback(localTryReadChar));
#else
solve();
#endif
return 0;
}
E. Number of Simple Paths
大致题意
给你一个 n n n个点 n n n条边的图,请问图上可以找出多少条不同的路径(无向图路径)
分析
首先这是一个等边数点数的图
这就意味着这个图有且仅有一个环
所以分析题意可知,这个图仅有一个环和一些“支链”组成
考虑环
对于一个环而言,任意两点间路径必定有两条,这是显而易见的
考虑支链
我们可以把支链看成一棵树,易得树上任意两点间的路径数仅一条
合并情况
对于现在题目给出的图而言,我们可以这样认为:
- 本来每两个点之间都有两条路径,即路径数为 n ∗ ( n − 1 ) n*(n-1) n∗(n−1)
- 但是部分的点恰好位于同一个支链上,我们知道支链其实是一棵树,树上任意两点间只有一条路径,那么我们刚才多加的路径需要减去,即减去 m ∗ ( m − 1 ) / 2 m*(m-1)/2 m∗(m−1)/2,其中 m m m为这个支链上的点数
那么问题就变成了,这个图上有多少条支链,每条支链有多少个点?
我选择用计数并查集加拓扑排序
AC code
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 200000 + 10;
struct Node {
int next;
int cnt;
} fa[MAXN];
int finds(int x) {
return x == fa[x].next ? x : fa[x].next = finds(fa[x].next);
}
void unions(int a, int b) {
int r1 = finds(fa[a].next);
int r2 = finds(fa[b].next);
if (r1 != r2) {
fa[r1].next = r2;
fa[r2].cnt += fa[r1].cnt;
}
}
void init(int b, int e) {
for (int i = b; i < e; i++) {
fa[i].next = i;
fa[i].cnt = 1;
}
}
int count(int k) {
return fa[finds(fa[k].next)].cnt;
}
void solve() {
int _;
cin >> _;
for (int ts = 0; ts < _; ++ts) {
int n;
cin >> n;
init(0, n + 1);
vector<vector<int>> g(n + 1);
vector<int> deg(n + 1, 0);
for (int i = 0; i < n; ++i) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
deg[u]++;
deg[v]++;
}
int ans = n * (n - 1);
queue<int> q;
vector<int> flower;
for (int i = 0; i < n + 1; ++i) if (deg[i] == 1) q.push(i);
while (!q.empty()) {
int cur = q.front();
q.pop();
for (auto &item : g[cur]) {
deg[item]--;
unions(cur, item);
if (deg[item] == 1) q.push(item);
}
}
for (int i = 0; i < n + 1; ++i) {
if (finds(i) != i) continue;
int tmp = count(i);
ans -= tmp * (tmp - 1) / 2;
}
cout << ans << endl;
}
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
#ifdef ACM_LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
signed localTestCount = 1, localReadPos = cin.tellg();
char localTryReadChar;
do {
if (localTestCount > 20)
throw runtime_error("Check the stdin!!!");
auto startClockForDebug = clock();
solve();
auto endClockForDebug = clock();
cout << "Test " << localTestCount << " successful" << endl;
cerr << "Test " << localTestCount++ << " Run Time: "
<< double(endClockForDebug - startClockForDebug) / CLOCKS_PER_SEC << "s" << endl;
cout << "--------------------------------------------------" << endl;
} while (localReadPos != cin.tellg() && cin >> localTryReadChar && localTryReadChar != '$' &&
cin.putback(localTryReadChar));
#else
solve();
#endif
return 0;
}
F. Array Partition
大致题意
给你一个序列,把它切成三分,使得切完后最左边的和最右边的两块的最大值等于中间那块的最小者
分析
首先题意中暗下说明了,这个值必须要在数列中出现三次以上
然后我的思路是
- 将遍历每个值,首先这个值得出现三次以上
- 将这个值的最左边的值 x x x 作为切开后最左边的那块的最大值,最右边的值 z z z 为切开后最右边的那块的最大值
- 那么我们假定 x 1 x1 x1为 x x x 右边第一个大于它的值, z 2 z2 z2 为 z z z 左边第一个大于它的值
- 我们遍历这个值出现的位置 y y y,除开第一个和最后一个,因为我们已经把它放在最左边那块和最右边那块里了
- 考虑对于 y y y 而言,左边第一个小于它的值的 y 1 y1 y1 和右边第一个小于它的值 y 2 y2 y2
- 如果满足 y 1 < x 1 a n d y 2 > z 2 y1 < x1 \space and \space y2 > z2 y1<x1 and y2>z2 那么一组合理的解就可以得到了
AC code
#include <bits/stdc++.h>
using namespace std;
void solve() {
int _;
cin >> _;
for (int ts = 0; ts < _; ++ts) {
int n;
cin >> n;
vector<int> data(n), lMin(n), rMin(n), lMax(n), rMax(n);
map<int, vector<int>> pos;
for (int i = 0; i < n; ++i) {
cin >> data[i];
auto iter = pos.find(data[i]);
if (iter == pos.end())
pos.insert({
data[i], {
i}});
else iter->second.push_back(i);
}
stack<int> st;
auto build = [&](vector<int> &res, int beg, int end, int step, function<bool(int, int)> cmp) {
for (int i = beg; i != end; i += step) {
while (!st.empty() && cmp(data[st.top()], data[i])) {
res[st.top()] = i;
st.pop();
}
st.push(i);
}
while (!st.empty()) {
res[st.top()] = end;
st.pop();
}
};
build(rMin, 0, n, 1, [&](int a, int b) {
return a > b; });
build(lMin, n - 1, -1, -1, [&](int a, int b) {
return a > b; });
build(rMax, 0, n, 1, [&](int a, int b) {
return a < b; });
build(lMax, n - 1, -1, -1, [&](int a, int b) {
return a < b; });
bool flag = false;
for (auto &iter : pos) {
if (flag) break;
if (iter.second.size() <= 2) continue;
if (lMax[iter.second.front()] != -1 || rMax[iter.second.back()] != n) continue;
int i = rMax[iter.second.front()], j = lMax[iter.second.back()];
for (int t = 1; t < iter.second.size() - 1; ++t) {
if (lMin[iter.second[t]] < i && rMin[iter.second[t]] > j) {
flag = true;
int a = max(lMin[iter.second[t]], iter.second.front()),
b = min(rMin[iter.second[t]], iter.second.back());
cout << "YES" << endl;
cout << a + 1 << ' ' << b - a - 1 << ' ' << n - b << endl;
break;
}
}
}
if (!flag) cout << "NO" << endl;
}
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
#ifdef ACM_LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
signed localTestCount = 1, localReadPos = cin.tellg();
char localTryReadChar;
do {
if (localTestCount > 20)
throw runtime_error("Check the stdin!!!");
auto startClockForDebug = clock();
solve();
auto endClockForDebug = clock();
cout << "Test " << localTestCount << " successful" << endl;
cerr << "Test " << localTestCount++ << " Run Time: "
<< double(endClockForDebug - startClockForDebug) / CLOCKS_PER_SEC << "s" << endl;
cout << "--------------------------------------------------" << endl;
} while (localReadPos != cin.tellg() && cin >> localTryReadChar && localTryReadChar != '$' &&
cin.putback(localTryReadChar));
#else
solve();
#endif
return 0;
}