topcoder srm 681 div1
problem1 link
二分答案。然后判断。将所有的机器按照$a_{i}$排序,$a_{i}$相同的按照$b_{i}$排序。用一个优先队列维护这些机器。这样对于第$i$个部分,拿出队列开始的机器来生产该部分;如果队列开头的机器生产的部分没用完,则将其左区间$a_{t}$设置为$a_{t}+1$然后重新塞到队列里。
problem2 link
首先由$A_{i}$得到$A_{i-1}$的方式为$A_{i-1}=((A_{i}+2^{50}-b)$^$a)$&$(2^{50}-1)$。然后就是一个数字一个数字暴力计算$B$值。总的累积复杂度是$O(n)$的。
problem3 link
令$f[i][j]$ 表示$vals[i]*vals[j]$对答案有贡献的概率。
令$dp[i][j][n]$表示$(i,j)$对答案有贡献且序列中总的元素个数为$n$的概率(那么$f[i][j]=dp[i][j][n]$)。考虑整个序列的长度从长度为 $n-1$转移到$n$。那么对于$dp[i][j][n]$来说,可以从下面三种情况转移而来:
(1)$dp[i-1][j-1][n-1]$: 在前面新增一个元素
(2)$dp[i][j-1][n-1]$: 在中间新增一个元素
(3)$dp[i][j][n-1]$: 在后面新增一个元素
code for problem1
#include <algorithm> #include <queue> #include <vector> class FleetFunding { public: int maxShips(int m, const std::vector<int> &k, const std::vector<int> &a, const std::vector<int> &b) { int n = static_cast<int>(k.size()); struct node { int L, R, cnt; node() = default; node(int L, int R, int cnt) : L(L), R(R), cnt(cnt) {} bool operator<(const node &A) const { if (L != A.L) return L > A.L; return R > A.R; } }; auto Check = [&](int M) { if (M == 0) { return true; } std::priority_queue<node> Q; for (int i = 0; i < n; ++i) { Q.push(node(a[i], b[i], k[i])); } for (int i = 1; i <= m; ++i) { if (Q.empty()) { return false; } int sum = 0; while (sum < M) { if (Q.empty() || Q.top().L != i) { return false; } if (sum + Q.top().cnt < M) { sum += Q.top().cnt; Q.pop(); } else { node p = Q.top(); Q.pop(); p.cnt -= M - sum; ++p.L; if (p.L <= p.R && p.cnt > 0) { Q.push(p); } break; } } while (!Q.empty() && Q.top().L == i) { node p = Q.top(); Q.pop(); ++p.L; if (p.L <= p.R) { Q.push(p); } } } return true; }; int sum = 0; for (int i = 0; i < n; ++i) { sum += k[i]; } int low = 0, high = sum / m; int result = 0; while (low <= high) { int M = (low + high) >> 1; if (Check(M)) { result = std::max(result, M); low = M + 1; } else { high = M - 1; } } return result; } };
code for problem2
class LimitedMemorySeries2 { public: int getSum(int n, long long x0, long long a, long long b) { constexpr int kMod = 1000000007; constexpr long long M = (1ll << 50) - 1; auto NextX = [&](long long x) { return ((x ^ a) + b) & M; }; auto PreX = [&](long long x) { return ((x + M + 1 - b) ^ a) & M; }; auto Cal = [&](int id, long long x, int n) { int ll = id, rr = id; int result = 0; long long lx = x, rx = x; while (ll - 1 >= 0 && rr + 1 < n) { lx = PreX(lx); rx = NextX(rx); if (lx < x && x > rx) { ++result; --ll; ++rr; } else { break; } } return result; }; int result = 0; long long t = x0; for (int i = 0; i < n; ++i) { result = (result + Cal(i, t, n)) % kMod; t = NextX(t); } return result; } };
code for problem3
#include <vector> class CoinFlips { public: double getExpectation(const std::vector<int> &vals, int prob) { const double p = prob / 1000000000.0; int n = static_cast<int>(vals.size()); std::vector<double> p2(n + 1); p2[0] = 1.0; for (int i = 1; i <= n; ++i) { p2[i] = p2[i - 1] * (1 - p); } std::vector<std::vector<double>> prefix(n + 1, std::vector<double>(n + 1)); std::vector<std::vector<double>> prefix_sum(n + 1, std::vector<double>(n + 1)); for (int len = 3; len <= n; ++len) { for (int i = 1; i <= len; ++i) { prefix[len][i] = p2[i - 1] * p; if (i == 1) { prefix[len][i] += p2[len]; } prefix_sum[len][i] = prefix_sum[len][i - 1] + prefix[len][i]; } } std::vector<std::vector<std::vector<double>>> f( 2, std::vector<std::vector<double>>(n + 1, std::vector<double>(n + 1))); int pre = 0, cur = 1; for (int len = 3; len <= n; ++len) { for (int i = 0; i <= n; ++i) { for (int j = 0; j <= n; ++j) { f[cur][i][j] = 0; } } for (int L = 1; L <= len; ++L) { for (int R = L + 2; R <= len; ++R) { f[cur][L][R] = prefix_sum[len][L - 1] * f[pre][L - 1][R - 1] + (prefix_sum[len][R - 1] - prefix_sum[len][L]) * f[pre][L][R - 1] + (1 - prefix_sum[len][R]) * f[pre][L][R]; if (L + 2 == R) { f[cur][L][R] += p2[L] * p; } } } pre ^= 1; cur ^= 1; } double result = 0.0; for (int i = 0; i < n; ++i) { for (int j = i + 2; j < n; ++j) { result += vals[i] * vals[j] * f[pre][i + 1][j + 1]; } } return result; } };