12 月上旬算法题集。
First One HDU - 5358
For each i, merge those j’s such that $[\log_2S(i, j)]$ get the same value. At most $\log_2(n·1e5)$ values will $[\log_2S(i, j)]$ have.
By using Prefix Sum and Binary Search, we can find those j’s in $O(log(n))$ .
The total time complexity is $O(n\log_2(n·1e5)log(n))$
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 #include <bits/stdc++.h> #define int long long using namespace std;inline int read () { int x = 0 , f = 1 ; char ch = getchar (); while (ch < '0' || ch > '9' ) { if (ch == '-' ) f = -1 ; ch = getchar (); } while (ch >= '0' && ch <= '9' ) { x = x * 10 + ch - 48 ; ch = getchar (); } return x * f; } int lg (int x) { if (x == 0 ) return 0 ; return 63 - __builtin_clzll(x); } void solve () { int n = read (), res = 0 ; vector<int >v (n + 1 , 0 ); for (int i = 1 ; i <= n; i++){ v[i] = v[i - 1 ] + read (); } for (int i = 1 ; i <= n; i++){ int ll = i - 1 ; for (int k = lg (v[i] - v[i - 1 ]); k <= lg (v[n]); k++){ int l = ll, r = n + 1 ; while (l + 1 != r){ int mid = l + r >> 1 ; if (v[mid] - v[i - 1 ] < (1ll << (k + 1 ))) l = mid; else r = mid; } res += (k + 1 ) * (i * (l - ll) + (ll + l + 1 ) * (l - ll) / 2 ); ll = l; } } cout << res << '\n' ; } signed main () { int t = read (); while (t--) solve (); return 0 ; }
Trapped in the Witch’s Labyrinth Codeforces Round 989 div1+2 C
Let’s consider those cells that can definitely escape:there must be a path leading to the border.
Thus, we can use a DFS in a reversed way, starting from points on the border(artificially added), recursively finding all cells that can escape from the boundary points.
Don’t forget, if a unspecified cell is surrounded by four points that can escape, it will exit too.
It’s easy to prove that, there is always a way to make the remaining cells being trapped forever: Two cells:point to each other. More cells:point to the two cells.
Implementation:
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 #include <bits/stdc++.h> #define int long long using namespace std;const int N = 1000 ;vector<vector<char >>mp (N + 2 , vector <char >(N + 2 )); vector<vector<int >>vis (N + 2 , vector <int >(N + 2 , 0 )); int cnt, n, m;void dfs (int x, int y) { vis[x][y] = 1 ; if (x == 0 ) { if (mp[x + 1 ][y] == 'U' && !vis[x + 1 ][y]) dfs (x + 1 , y); } else if (x == n + 1 ) { if (mp[x - 1 ][y] == 'D' && !vis[x - 1 ][y]) dfs (x - 1 , y); } else if (y == 0 ) { if (mp[x][y + 1 ] == 'L' && !vis[x][y + 1 ]) dfs (x, y + 1 ); } else if (y == m + 1 ) { if (mp[x][y - 1 ] == 'R' && !vis[x][y - 1 ]) dfs (x, y - 1 ); } else { cnt++; if (mp[x + 1 ][y] == 'U' && !vis[x + 1 ][y]) dfs (x + 1 , y); if (mp[x - 1 ][y] == 'D' && !vis[x - 1 ][y]) dfs (x - 1 , y); if (mp[x][y + 1 ] == 'L' && !vis[x][y + 1 ]) dfs (x, y + 1 ); if (mp[x][y - 1 ] == 'R' && !vis[x][y - 1 ]) dfs (x, y - 1 ); } } void solve () { cnt = 0 ; cin >> n >> m; for (int i = 0 ; i <= n + 1 ; i++){ for (int j = 0 ; j <= m + 1 ; j++){ mp[i][j] = '0' ; vis[i][j] = 0 ; } } for (int i = 1 ; i <= n; i++) { for (int j = 1 ; j <= m; j++) { cin >> mp[i][j]; vis[i][j] = 0 ; } } for (int j = 1 ; j <= m; j++) { dfs (0 , j), dfs (n + 1 , j); } for (int i = 1 ; i <= n; i++) { dfs (i, 0 ), dfs (i, m + 1 ); } for (int i = 1 ; i <= n; i++) { for (int j = 1 ; j <= m; j++) { if (mp[i][j] == '?' && vis[i - 1 ][j] && vis[i + 1 ][j] && vis[i][j - 1 ] && vis[i][j + 1 ]) vis[i][j] = 1 , cnt++; } } cout << n * m - cnt << '\n' ; } signed main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int t; cin >> t; while (t--) solve (); return 0 ; }
Darius’ Wisdom Codeforces Round 989 div1+2 D
Construction problem.
We can easily find the final condition of the array. Then do the following steps:
Put every 0 in its right position. Since 1 always exsits, by using 1, it takes at most 2count(0)
steps.
The rest of array only contains 1 and 2. To sort this part of array, we need at most min(count(1), count(2))
steps.
2count(0) + min(count(1), count(2))
is certainly too much, we need to lower it to less than n.
Assume we have count(0) <= count(2)
(0 and 2 are equivalent, if not satisfied, just exchange 0 and 2 is ok)
Through mathematical calculations 2count(0) + min(count(1), count(2)) <= count(0) + max(count(1), count(2)) + min(count(1) + count(2)) = count(0) + count(1) + count(2) = n
Implementation:
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 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 #include <bits/stdc++.h> using namespace std;typedef pair<int , int > PII;inline int read () { int x = 0 , f = 1 ; char ch = getchar (); while (ch < '0' || ch > '9' ) { if (ch == '-' ) f = -1 ; ch = getchar (); } while (ch >= '0' && ch <= '9' ) { x = x * 10 + ch - 48 ; ch = getchar (); } return x * f; } void solve () { int n = read (); int x = 0 , y = 0 , z = 0 , pos; vector<int >v (n + 1 ); for (int i = 1 ; i <= n; i++) { v[i] = read (); if (v[i] == 0 ) x++; if (v[i] == 1 ) y++, pos = i; if (v[i] == 2 ) z++; } int cnt = 0 ; vector<PII>res; if (x <= z){ for (int i = 1 , j = x + 1 ;;){ while (i <= x && v[i] == 0 ){ i++; } while (j <= n && v[j] != 0 ){ j++; } if (i > x || j > n) break ; if (v[i] == 1 ){ cnt++; swap (v[i], v[j]); res.emplace_back (i, j); pos = j; } else if (v[i] == 2 ){ cnt += 2 ; swap (v[i], v[pos]); swap (v[i], v[j]); res.emplace_back (i, pos); res.emplace_back (i, j); pos = j; } } for (int i = x + 1 , j = x + y + 1 ;;){ while (i <= x + y && v[i] == 1 ){ i++; } while (j <= n && v[j] == 2 ){ j++; } if (i > x + y || j > n) break ; cnt++; swap (v[i], v[j]); res.emplace_back (i, j); } } else { for (int i = x + y + 1 , j = 1 ;;){ while (i <= n && v[i] == 2 ){ i++; } while (j <= x + y && v[j] != 2 ){ j++; } if (i > n || j > x + y) break ; if (v[i] == 1 ){ cnt++; swap (v[i], v[j]); res.emplace_back (i, j); pos = j; } else if (v[i] == 0 ){ cnt += 2 ; swap (v[i], v[pos]); swap (v[i], v[j]); res.emplace_back (i, pos); res.emplace_back (i, j); pos = j; } } for (int i = x + 1 , j = 1 ;;){ while (i <= x + y && v[i] == 1 ){ i++; } while (j <= x && v[j] == 0 ){ j++; } if (i > x + y || j > x) break ; cnt++; swap (v[i], v[j]); res.emplace_back (i, j); } } cout << cnt << '\n' ; for (auto &u : res){ cout << u.first << ' ' << u.second << '\n' ; } } signed main () { int t = read (); while (t--) solve (); return 0 ; }
Recommendations Educational Codeforces Round 172 (div.2) D
For each segment, we need to find the minimum l
and the maximum r
of its predictor.
The first round, sort the segments in l
ascending , r
descending order. Using Binary Search to find the min{r}
of one’s predictors. Then add its r
into the set. In this way, we can always find the min{r}
of each segment.
The second round, sort the segments in r
descending, l
ascending order. With similar handling method, we can find the max{l}
of each segment.
Pay attention to the situation that serveral segments are exactly the same: we need to help the first handled segment to change its max{l}
and min{r}
to l
and r
of its own.
Implementation:
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 #include <bits/stdc++.h> using namespace std;typedef pair<int , int >PII;inline int read () { int x = 0 , f = 1 ; char ch = getchar (); while (ch < '0' || ch > '9' ) { if (ch == '-' ) f = -1 ; ch = getchar (); } while (ch >= '0' && ch <= '9' ) { x = x * 10 + ch - 48 ; ch = getchar (); } return x * f; } void solve () { int n = read (); vector<int >l (n), r (n); for (int i = 0 ; i < n; i++){ l[i] = read (), r[i] = read (); } vector<int > L (n, -1 ) , R (n, -1 ) ; vector<int > p (n) ; iota (p.begin (), p.end (), 0 ); { sort (p.begin (), p.end (), [&](int i, int j){ if (l[i] != l[j]) return l[i] < l[j]; return r[i] > r[j]; }); set<int > s; for (int j = 0 ; j < n; j++){ int i = p[j]; auto it = s.lower_bound (r[i]); if (it != s.end ()){ R[i] = *it; } if (j + 1 < n && l[i] == l[p[j + 1 ]] && r[i] == r[p[j + 1 ]]){ R[i] = r[i]; } s.emplace (r[i]); } } { sort (p.begin (), p.end (), [&](int i, int j){ if (r[i] != r[j]) return r[i] > r[j]; return l[i] < l[j]; }); set<int > s; for (int j = 0 ; j < n; j++){ int i = p[j]; auto it = s.upper_bound (l[i]); if (it != s.begin ()){ L[i] = *prev (it); } if (j + 1 < n && l[i] == l[p[j + 1 ]] && r[i] == r[p[j + 1 ]]){ L[i] = l[i]; } s.emplace (l[i]); } } for (int i = 0 ; i < n; i++){ if (L[i] == -1 ){ cout << 0 << '\n' ; } else { cout << (R[i] - L[i]) - (r[i] - l[i]) << '\n' ; } } } signed main () { int t = read (); while (t--) solve (); return 0 ; }
Move Back at a Cost Codeforces Round 990 div1 B (div2 D)
Ascending array (call it stk
) should be saved.
The rest elements (call it b
) should be put back in ascending order, and when the tail of stk
is smaller then the head of b
, it should also join b
and finally be put in the back of array.
Implementation:
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 #include <bits/stdc++.h> #define int long long using namespace std;inline int read () { int x = 0 , f = 1 ; char ch = getchar (); while (ch < '0' || ch > '9' ) { if (ch == '-' ) f = -1 ; ch = getchar (); } while (ch >= '0' && ch <= '9' ) { x = x * 10 + ch - 48 ; ch = getchar (); } return x * f; } void solve () { int n = read (); vector<int >a (n); for (auto &i : a) i = read (); vector<int >stk, b; for (int i = 0 ; i < n; i++){ while (!stk.empty () && stk.back () > a[i]){ b.emplace_back (stk.back () + 1 ); stk.pop_back (); } stk.emplace_back (a[i]); } sort (b.begin (), b.end ()); while (!b.empty () && stk.back () > b[0 ]){ b.emplace_back (stk.back () + 1 ); stk.pop_back (); } sort (b.begin (), b.end ()); a = stk; for (auto &i : b) a.emplace_back (i); for (int i = 0 ; i < n; i ++){ cout << a[i] << " \n" [i == n - 1 ]; } } signed main () { int t = read (); while (t--) solve (); return 0 ; }
Expansion Packs Atcoder ABC 382 E
dp[i]
means the probability to get i
rare cards in one pack. Not difficult to update dp[i]
by the given probabilities. (Refering the implementation)
f[x]
means the expected number to get x
rare cards.
If i <= 0
, f[i] = 0
. The recurrence formula: $$ f[x]=\sum_{i=0}^ndp[i]\times(1+f[x-i]) $$ That is: $$ f[x]=\frac{1+\sum_{i=1}^ndp[i]\times f[x-i]}{1-dp[0]} $$ Implementation:
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 #include <bits/stdc++.h> using namespace std;void solve () { int n, x; cin >> n >> x; vector<double >dp (n + 1 , 0 ); dp[0 ] = 1 ; for (int i = 0 ; i < n; i++){ int q; cin >> q; double p = 0.01 * q; for (int j = i; j >= 0 ; j--){ dp[j + 1 ] += dp[j] * p; dp[j] *= 1 - p; } } double s = 1 - dp[0 ]; vector<double > f (x + 1 ) ; for (int i = 1 ; i <= x; i++) { for (int j = 1 ; j <= n; j++) { f[i] += f[max (i - j, 0 )] * dp[j]; } f[i] += 1 ; f[i] /= 1 - dp[0 ]; } cout << fixed << setprecision (17 ) << f[x] << '\n' ; } signed main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int t = 1 ; while (t--) solve (); return 0 ; }
9 Divisors Atcoder ABC 383 D
$9=(1+8)=(1+2)*(1+2)$
It means if a number has 9 divisors, it can be expressed by $p_1^8$ or $p_1^2p_2^2$
($p_i$ is a random prime number)
Init all the satisfied number and use binary search to get the answer.
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 #include <bits/stdc++.h> #define int long long using namespace std;inline int read () { int x = 0 , f = 1 ; char ch = getchar (); while (ch < '0' || ch > '9' ) { if (ch == '-' ) f = -1 ; ch = getchar (); } while (ch >= '0' && ch <= '9' ) { x = x * 10 + ch - 48 ; ch = getchar (); } return x * f; } const int MX = 4e12 ;const int N = 2e6 +5 ;int primes[N], cnt;bool comp[N];vector<int >v; void Euler (int n) { for (int i = 2 ; i <= n; i++){ if (!comp[i]) primes[cnt++] = i; for (int j = 0 ; primes[j] <= n / i; j++){ comp[i * primes[j]] = 1 ; if (!(i % primes[j])) break ; } } } void init () { Euler (2000000 ); for (int i = 2 ; i < 40 ; i++){ if (comp[i]) continue ; int u = i * i * i * i * i * i * i * i; if (u <= MX){ v.emplace_back (u); } } for (int i = 0 ; i < cnt; i++){ if (primes[i] > 2000 ) break ; for (int j = i + 1 ; j < cnt; j++){ int u = primes[i] * primes[i] * primes[j] * primes[j]; if (u > MX) break ; v.emplace_back (u); } } sort (v.begin (), v.end ()); } void solve () { int n = read (); cout << upper_bound (v.begin (), v.end (), n) - v.begin (); } signed main () { init (); solve (); return 0 ; }
阿兔与种树 牛客 - 浙江机电职业技术大学第九届程序设计竞赛 J
每次修改在原序列 s
上放入一个等差数列 1, 2, ... , n
。
不妨考察其差分形式 1, 1, ... , 1, -n
依然不方便整体修改,继续考察差分数列的差分 1, 0, ..., 0, -n - 1, n
这样,每次修改时在该二维差分上操作即可。
实现:
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> #define int long long using namespace std;inline int read () { int x = 0 , f = 1 ; char ch = getchar (); while (ch < '0' || ch > '9' ) { if (ch == '-' ) f = -1 ; ch = getchar (); } while (ch >= '0' && ch <= '9' ) { x = x * 10 + ch - 48 ; ch = getchar (); } return x * f; } signed main () { int n = read (), m = read (); vector<int >dd (n + 3 , 0 ), d (n + 3 , 0 ), s (n + 3 , 0 ); for (int i = 0 ; i < m; i++){ int l = read (), r = read (); dd[l]++; dd[r + 1 ] -= r - l + 2 ; dd[r + 2 ] += r - l + 1 ; } for (int i = 1 ; i <= n; i++){ d[i] = d[i - 1 ] + dd[i]; } for (int i = 1 ; i <= n; i++){ s[i] = s[i - 1 ] + d[i]; } for (int i = 1 ; i <= n; i++){ cout << s[i] << ' ' ; } return 0 ; }