VP了一场
1279A New Year Garland 有三种东西,分别$a,b,c$个,问能不能组成相同物品不相邻的一列。
挑最大的把其他插到最大的间隔里就行,$O(1)$。
A.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <bits/stdc++.h> using namespace std ; int main () { int q; cin >> q; while (q--) { int a[3 ]; cin >> a[0 ] >> a[1 ] >> a[2 ]; sort(a, a + 3 ); if (a[0 ] + a[1 ] < a[2 ] - 1 ) puts ("No" ); else puts ("Yes" ); } return 0 ; }
1279B Verse For Santa 有$n$个物品,各自有长度,依次的放在长$s$内,现在可以省略一个,问最多放几个。
贪心比较,如果有必要省略必定省去最长的,否则不省略,$O(n)$。
B.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <bits/stdc++.h> using namespace std ;const int N = 3e5 + 5 ; int a[N]; int main () { int q; cin >> q; while (q--) { int n, k, ans = 0 ; cin >> n >> k; for (int i = 1 ; i <= n; ++i) { cin >> a[i]; } ll sum = 0 , la = 0 ; for (int i = 1 ; i <= n; ++i) { if (la < a[i]) { sum += la; la = a[i]; if (sum > k) break ; ans = i; } else sum += a[i]; if (sum > k) break ; } if (k - sum >= la) ans = 0 ; cout << ans << endl ; } return 0 ; }
1279C Stack of Presents 有一个长$n$的排列,从右到左压到栈里,现在要取出$m$个数,如果这个数上面有$k$个数,需要花$2k+1$秒,但在放回$k$个数时,可以按任意顺序放回,问取出$m$个数的最小耗时。
在取出一个较深的数的时候,前面的数我们可以按照被取的顺序,倒序放回,这样取它的时候就会在栈顶。那么维护一个最深操作的深度,在操作比这个位置深得数的代价就是$2k+1$,否则代价是$1$,$O(n+m)$
C.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <bits/stdc++.h> using namespace std ;const int N = 3e5 + 5 ;int pos[N];int main () { int q; cin >> q; while (q--) { int n, m, la = 0 ; cin >> n >> m; for (int i = 1 , t; i <= n; ++i) { cin >> t; pos[t] = i; } ll ans = 0 ; for (int i = 1 , t; i <= m; ++i) { cin >> t; if (pos[t] < la) ++ans; else ans += 2 * (pos[t] - i) + 1 ; la = max (la, pos[t]); } cout << ans << endl ; } return 0 ; }
1279D Santa’s Bot 圣诞老人用机器人发礼物,有$n$个小孩,每个小孩有$k_i$个愿望。但是机器人会随机的选一个小孩$x$,再随机选他的一个愿望$y$,再随机发给某个小孩$z$,假如$y$确实是$z$的愿望之一,那么这样的一个三元组$(x,y,z)$就是正确的,问机器人选出正确三元组的概率。
因为愿望最多不超过$10^6$,所有我们枚举愿望。选中一个孩子的概率是$\frac 1n$,选他的一个愿望被选中的概率是$\frac 1{k_i}$,统计想要这个礼物的孩子个数$cnt[j]$,那么发送正确的概率是$\frac {cnt[j]}n$,因为每个情况独立,可以相加,$O(\sum k_i)$。
D.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include <bits/stdc++.h> using namespace std; const int mod = 998244353 ; const int N = 1 e6 + 5 ; vector<int > gift[N ]; ll cnt[N ], inv[N ]; void init() { inv[1 ] = 1 ; for (int i = 2 ; i <= 1 e6; ++i) { inv[i] = (mod - mod / i) * inv[mod % i] % mod ; } } int main() { init(); int n ; cin >> n ; for (int i = 0 , t ; i < n ; ++i) { cin >> t ; gift[i].resize(t ); for (int &j : gift[i]) { cin >> j; ++cnt[j]; } } int ans = 0 ; for (int i = 0 ; i < n ; ++i) { int tmp = 0 ; for (int j : gift[i]) tmp += cnt[j]; ans = (ans + inv[gift[i].size()] * tmp % mod ) % mod ; } ans = ans * inv[n ] % mod * inv[n ] % mod ; cout << ans << endl; return 0 ; }
1279E New Year Permutations 题意比较难描述,建议看原文 /翻译
首先考虑一个长$n$的大环有多少排列,因为$n$一定是开头,$1$一定是$n$的前驱,之后剩下的$n-2$个点可以任意排,即$(n-2)!$。现在设$dp[i]$表示长为$i$的串有多少种合法排列,转移方程即:
然后我们可以通过从字典序由小到大枚举,得到第$k$大的排列由哪些长度小序列组成。根据这一步得到的结果,问题被分解成了长为$l$的环,$l$位置固定,$1$固定是$l$前驱,字典序的第$x$个环是哪个(在按位枚举字典序的时候其实就是空闲位的阶乘,枚举的过程中要保证不能形成小环,即长度必须是上一步算出的结果),那么拼起来就可以得到最终答案,$O(n^2)$
E.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 #include <bits/stdc++.h> using namespace std ;int ans[55 ], fa[55 ], vis[55 ];ll dp[55 ], fac[55 ]; inline ll calc (int x) { x -= 2 ; if (x < 0 ) return 1 ; return fac[x]; } void init () { fac[0 ] = 1 ; for (int i = 1 ; i < 20 ; ++i) fac[i] = fac[i - 1 ] * i; for (int i = 20 ; i <= 50 ; ++i) fac[i] = 1e18 ; dp[0 ] = 1 ; for (int i = 1 ; i < 22 ; ++i) { for (int j = 0 ; j < i; ++j) dp[i] += dp[j] * calc(i - j); } for (int i = 22 ; i <= 50 ; ++i) { dp[i] = 1e18 ; } } int fi (int x) { if (x != fa[x]) return fa[x] = fi(fa[x]); return x; } void permute (int l, int r, ll rk) { ans[l] = r; vis[r] = 1 ; int x = r - l - 2 ; for (int i = l + 1 ; i <= r; ++i) { for (int j = l; j <= r; ++j) { if (i == r && !vis[j]) { ans[i] = j; break ; } if (vis[j] || fi(i) == fi(j)) continue ; if (x < 0 ) x = 0 ; if (fac[x] >= rk) { --x; ans[i] = vis[j] = j; fa[fi(j)] = fi(i); break ; } else rk -= fac[x]; } } } int main () { init(); int q; cin >> q; while (q--) { int n; ll k; cin >> n >> k; if (k > dp[n]) { cout << -1 << endl ; continue ; } for (int i = 1 ; i <= n; ++i) { vis[i] = 0 ; fa[i] = i; } for (int l = 1 , r; l <= n; l = r + 1 ) { for (r = l; r <= n; ++r) { ll term = calc(r - l + 1 ) * dp[n - r]; if (term >= k) break ; k -= term; } ll rk = (k - 1 ) / dp[n - r] + 1 ; k = (k - 1 ) % dp[n - r] + 1 ; permute(l, r, rk); } for (int i = 1 ; i <= n; ++i) cout << ans[i] << ' ' ; cout << endl ; } return 0 ; }
1279F New Year and Handle Change 有一个字符串,含有大小写字母,每次操作可以把长为$l$的一段字母全变成大写或小写,问最后能得到的$min$(大写字母,小写字母)的值。
挂个链,有缘回来看。题解
本文标题: Educational Codeforces Round 79 题解
文章作者: WGree
发布时间: 2020-04-03
最后更新: 2020-04-05
原始链接: https://blog.wgree.site/3592098837/
版权声明: 禁止转载