A. Fibonacciness
题意:给你\(a_1,a_2,a_4,a_5\),你可以让\(a_3\)等于任何数,求最大有多少个\(i\)满足\(1 <= i <= 3, a_i + a_{i+1} = a_{i+2}\)。
枚举\(a_3\)分别等于\(a_1 + a_2,a_4 - a_2, a_5 - a_4\)的情况取最大值即可。
点击查看代码
void solve() {int a, b, c, d;std::cin >> a >> b >> c >> d;int ans1 = 1;if (b + a + b == c) {++ ans1;}if (a + b + c == d) {++ ans1;}int ans2 = 1;if (b + d - c == c) {++ ans2;}if (a + b == d - c) {++ ans2;}int ans3 = 1;if (a + b == c - b) {++ ans3;}if (c - b + c == d) {++ ans3;}std::cout << std::max({ans1, ans2, ans3}) << "\n";
}
B. Farmer John's Card Game
题意:\(n \times m\)个牌分在\(n\)个人手里,每人手里\(m\)个,要有一个排列使得按照这个排列上的顺序出牌,让所有人都可以出完,出牌规则是要等于上一个人出的牌。
要出完所有牌,那么打出的牌肯定是\(n*m\)个牌按从小到大顺序出。那么从小到大枚举,看当前出这个牌的人上次出牌是不是在\(i-n\)之前就行,因为一轮是\(n\)个人,总共\(m\)轮正好出完,所以一个人如果在一轮出两张以上的牌那么会有一个人有牌出不来。
点击查看代码
void solve() {int n, m;std::cin >> n >> m;std::vector<int> a(n * m);for (int i = 0; i < n; ++ i) {for (int j = 0; j < m; ++ j) {int x;std::cin >> x;a[x] = i;}}std::vector<int> ans(n), last(n, -n);for (int i = 0; i < n * m; ++ i) {if (i - last[a[i]] < n) {std::cout << -1 << "\n";return;}last[a[i]] = i;if (i < n) {ans[i] = a[i];}}for (int i = 0; i < n; ++ i) {std::cout << ans[i] + 1 << " \n"[i == n - 1];}
}
C. Game of Mathletes
有n个数,每次\(Alice\)选一个数\(a\),\(Bob\)选一个数\(b\),如果\(a+b=k\),那么分数加一,问最终分数。
分数是固定的,因为如果牌库里有\(k-a\)那么\(Bob\)一定会选。那么计算每个\(a\)和\(k-a\)能产生的贡献即可。
点击查看代码
void solve() {int n, k;std::cin >> n >> k;std::vector<int> cnt(2 * n + 1);for (int i = 0; i < n; ++ i) {int x;std::cin >> x;++ cnt[x];}int ans = 0;for (int i = 1; i <= k / 2; ++ i) {if (k % 2 == 0 && i == k / 2) {ans += cnt[i] / 2;} else {ans += std::min(cnt[i], cnt[k - i]);}}std::cout << ans << "\n";
}
D. Subtract Min Sort
题意:一个数组\(a\),你每次可以让两个相邻的数一起减去他们之中的最小值。问能不能是数组非递减。
假设\([1,i]\)已经非递减,那么如果\(a_i>a_{i+1}\),那么操作\(i\)和\(i+1\)是没用的,只能操作\(i-1\)和\(i\),所以让\(a_i-=a_{i-1}\)。如果\(a_i<=a_{i+1}\),如果我们不操作的话,遇到\(a_{i+1}>a_{i+2}\),那么只操作\(i,i+1\)是不够的,因为这样后\(a_i=0\),而\(a_{i-1} > a_i\),所以还是得让\(a_i-=a_{i+1}\)。如果后面没有出现递减的情况,那么我们这样操作也不会影响数组。所以每次都让\(a_i-=a_{i-1}\)。
注意特判\(a_1 > a_2\)的情况。
点击查看代码
void solve() {int n;std::cin >> n;std::vector<int> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}if (a[0] > a[1]) {std::cout << "NO\n";return;}for (int i = 1; i + 1 < n; ++ i) {a[i] -= a[i - 1];if (a[i] > a[i + 1]) {std::cout << "NO\n";return;}}std::cout << "YES\n";
}
E. Graph Composition
题意:给你两个图\(f,g\),你可以每次操作给\(f\)加一条边或者减一条边。问让两个图任意两个点联通性相同需要的最小操作数。
我们给两个图都开一个并查集记录集合。我们用\(f_u, g_u\)表示点\(u\)在两个点所在的集合。
首先如果\((u, v) \in f\),并且\(g_u \neq g_v\),那么这条边一定要删。
然后枚举\(g\)的每个集合,如果有一个\(v \in g_u\)并且\(v \notin f_u\),那么要加一条边,同时在\(f\)的集合里合并\(f_u\)和\(f_v\)。
点击查看代码
void solve() {int n, m, k;std::cin >> n >> m >> k;std::set<std::pair<int, int> > s1, s2;std::vector<int> fa1(n + 1), fa2(n + 1);std::iota(fa1.begin(), fa1.end(), 0);std::iota(fa2.begin(), fa2.end(), 0);std::function<int(int)> find1 = [&](int x) -> int {return x == fa1[x] ? x : fa1[x] = find1(fa1[x]);};std::function<int(int)> find2 = [&](int x) -> int {return x == fa2[x] ? x : fa2[x] = find2(fa2[x]);};for (int i = 0; i < m; ++ i) {int u, v;std::cin >> u >> v;s1.insert({u, v});}for (int i = 0; i < k; ++ i) {int u, v;std::cin >> u >> v;fa2[find2(u)] = find2(v);s2.insert({u, v});}int ans = 0;for (auto & [x, y] : s1) {if (find2(x) != find2(y)) {++ ans;} else {fa1[find1(x)] = find1(y);}}std::map<int, std::vector<int> > mp;for (int i = 1; i <= n; ++ i) {mp[find2(i)].push_back(i);}for (int i = 1; i <= n; ++ i) {for (auto & x : mp[i]) {if (find1(x) != find1(i)) {++ ans;fa1[find1(x)] = find1(i);}}}std::cout << ans << "\n";
}
F. Multiplicative Arrays
神秘dp,不会
待补