topcoder srm 640 div1
problem1 link
首先使用兩個端點顏色不同的邊進行連通。答案是$n-1-m$。其中$m$是聯通分量的個數。
problem2 link
首先構造一個最小割的模型。左邊的$n_{1}$個點與源點相連,右邊的$n_{2}$個點與匯點相連。每個中間點最少有$d+1$條邊(有一條到匯點/源點的邊)。最小割為$ans$.
假設有$x$個割邊出現在源點和$n_{1}$之間,那麼$y=ans-x$個出現在$n_{2}$和匯點之間。其中$x,y$應該滿足的關係為$0\leq y=ans-x \leq n_{2},0\leq x \leq n_{1},and\leq min(n_{1},n_{2})\rightarrow 0\leq x \leq ans$
左邊剩下的$n_{1}-x$個點與右邊剩下的$n_{2}-y$個點之間不能有邊存在,否則最小割會變大。所以總的邊的數量為$f(x)=n_{1}n_{2}-(n_{1}-x)(n_{2}-y)=n_{1}n_{2}-(n_{1}-x)(n_{2}-(ans-x))$
$f(x)$的最大值在$x=\frac{n_{1}-n_{2}+ans}{2}$時取得。
$0 \leq x=\frac{n_{1}-n_{2}+ans}{2} \leq ans\rightarrow -ans\leq n_{1}-n_{2}\leq ans$。當$n_{1}-n_{2}$不在這個範圍時,列舉邊界即可。
problem3
如果兩個數字$x,y$的差$x-y$能被數$p$整除,那麼有$x\equiv y(mod(p))$。
所以可以對每個素數計算有那些數對$(A_{i},B_{j})$的餘數相等,他們的差值就含有素數$p$。最後就剩下那些素數特別大的。
這個題目應該有幾組特別刁鑽的測試資料,程式碼一直超時。
code for problem1
#include <vector> class ChristmasTreeDecoration { public: int solve(const std::vector<int> &col, const std::vector<int> &x, const std::vector<int> &y) { int n = static_cast<int>(col.size()); int m = static_cast<int>(x.size()); father_.resize(n); for (int i = 0; i < n; ++i) { father_[i] = i; } int number = 0; for (int i = 0; i < m; ++i) { int u = x[i] - 1; int v = y[i] - 1; if (col[u] != col[v]) { int pu = GetRoot(u); int pv = GetRoot(v); if (pu != pv) { father_[pu] = pv; ++number; } } } return n - 1 - number; } private: int GetRoot(int x) { if (father_[x] == x) { return x; } return father_[x] = GetRoot(father_[x]); } std::vector<int> father_; };
code for problem2
#include <algorithm> class MaximumBipartiteMatchingProblem { public: long long solve(int n1, int n2, int ans, int d) { long long result = -1; auto Update = [&](int x) { if (x < d || ans - x < d) { return; } result = std::max(result, 1ll * n2 * x + 1ll * (n1 - x) * (ans - x)); }; if (n1 > n2) { std::swap(n1, n2); } if (n1 == ans) { return 1ll * n1 * n2; } Update(0); Update(d); Update(ans - d); Update(n1); Update(n2); Update((ans + n1 - n2) / 2); Update((ans + n1 - n2) / 2 + 1); return result; } };
code for problem3
#include <algorithm> #include <vector> constexpr int kMax = 1000; constexpr int kMaxPrime = 31622; int diff[kMax][kMax]; int values[kMax][kMax]; int nxt[kMax]; int head[kMaxPrime]; int tag[kMaxPrime]; int prime_tag[kMaxPrime]; class TwoNumberGroups { static constexpr int kMod = 1000000007; public: int solve(const std::vector<int> &A, const std::vector<int> &numA, const std::vector<int> &B, const std::vector<int> &numB) { int n = static_cast<int>(A.size()); int m = static_cast<int>(B.size()); for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { diff[i][j] = std::abs(A[i] - B[j]); } } int result = 0; for (int p = 2; p < kMaxPrime; ++p) { if (prime_tag[p] != 1) { for (int x = p + p; x < kMaxPrime; x += p) { prime_tag[x] = 1; } for (int i = 0; i < n; ++i) { int t = A[i] % p; if (tag[t] != p) { head[t] = -1; tag[t] = p; } nxt[i] = head[t]; head[t] = i; } for (int i = 0; i < m; ++i) { int t = B[i] % p; if (tag[t] == p) { for (int j = head[t]; j != -1; j = nxt[j]) { if (A[j] != B[i]) { values[j][i] += p; while (diff[j][i] % p == 0) { diff[j][i] /= p; } } } } } } } for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { if (diff[i][j] > 1) { values[i][j] += diff[i][j]; } result += 1ll * numA[i] * numB[j] % kMod * values[i][j] % kMod; if (result >= kMod) { result -= kMod; } } } return result; } };