topcoder srm 635 div1

problem1 linkcode

首先枚舉長度$L$。而後計算每一段長度$L$的差值最大公約數,而後差值除以最大公約數的結果能夠做爲當前段的關鍵字。而後不一樣段就能夠比較他們的關鍵字,同樣就是能夠轉化的。blog

problem2 linkget

對於那些必定要換的,把它們的places和cutoff拿出來,排個序。設它們爲$p_{1},p_{2},..,p_{k},c_{1},c_{2},..,c_{k},$.最優的策略必定是從小到大挨個匹配。it

若是到了某個位置不能匹配,好比$t$.那麼須要從那些不須要交換的組裏面拿出一個$(np,nc)$,這個須要知足$np\leq c_{t}$而且$nc$儘可能大。ast

problem3 linkclass

 因爲會有兩個值不大於200,那麼這兩種最後會把整個序列最多分爲401段。而後就是考慮把後面的兩種也分紅這麼多段插進去就好。date

第一個問題,假設$f[n][m][k]$表示第一個顏色和第二個顏色各有$n$和$m$個,分紅$k$段的方案數。有一個性質是每一段兩個是交錯的,因此數量差不會超過1,那麼能夠獲得轉移方程:方法

(1)兩個同樣多組成一段:$n>0, m>0\rightarrow f[n][m][k]=2\sum_{i=1}^{min(n,m)}f[n-i][m-i][k-1]$im

(2)第一個多一個組成一段:$n>0\rightarrow f[n][m][k]=\sum_{i=1}^{min(n-1,m)}f[n-1-i][m-i][k-1]$sort

(3)第二個多一個組成一段:$m>0\rightarrow f[n][m][k]=\sum_{i=1}^{min(n,m-1)}f[n-i][m-1-i][k-1]$

因此能夠預處理對角線的前綴和能夠在$O(nm(n+m))$的複雜度的計算完$f$

第二個問題,假設如今有$m$段,將後面兩個插進去,有多少方法。這$m$段有三種狀況,第一種第三個顏色的數量多一個,第二種第四個顏色的數量多一個,第三種兩種顏色同樣多。設第三種顏色第四種顏色的數量分別爲$a,b,a\leq b$。這三種段的數量分別爲$t,p,q$,那沒有$t+p+q=m,p-t=b-a$。因此能夠枚舉$t$,而後$p,q$就能夠都肯定。令$X=a-t=b-p$,剩下的問題就是將$X$分紅$m$個數字之和使得前$t+p$個數字能夠爲0,後面$q$個數字不能爲0.這等價於將$Y=X+t+p-m$個數字分紅$m$個數字之和,每一個數字大於等於0.答案爲$C_{Y+m-1}^{m-1}=C_{X+t+p-m-m-1}^{m-1}=C_{a-t+t+p-m+m-1}^{m-1}=C_{a+p-1}^{m-1}$

因此$G(m,a,b)=\sum_{t=0}^{min(a,m)}C_{m}^{t}*C_{m-t}^{p}*2^{q}*C_{a+p-1}^{m-1}[q\geq 0]$

code for problem1

#include <cmath>
#include <vector>

class SimilarRatingGraph {
 public:
  double maxLength(const std::vector<int> &date,
                   const std::vector<int> &rating) {
    int n = static_cast<int>(date.size());
    auto Length = [&](int idx) {
      double x = date[idx] - date[idx - 1];
      double y = rating[idx] - rating[idx - 1];
      return std::sqrt(x * x + y * y);
    };
    double result = 0;
    for (int L = n - 1; L > 1; --L) {
      int m = n - L + 1;
      std::vector<std::pair<long long, long long>> sum(m);
      for (int i = 0; i + L <= n; ++i) {
        int g = 0;
        for (int j = i + 1; j < i + L; ++j) {
          g = Gcd(g, date[j] - date[j - 1]);
          g = Gcd(g, std::abs(rating[j] - rating[j - 1]));
        }
        long long s0 = 0;
        long long s1 = 0;
        for (int j = i + 1; j < i + L; ++j) {
          int t0 = (date[j] - date[j - 1]) / g;
          int t1 = (rating[j] - rating[j - 1]) / g;
          s0 = s0 * 100007 + t0 + (j - i);
          s1 = s1 * 100007 + t1 + (j - i);
        }
        sum[i] = {s0, s1};
      }
      std::vector<double> sum_length(m, 0);
      for (int i = 1; i < L; ++i) {
        sum_length[0] += Length(i);
      }
      for (int i = 1; i < m; ++i) {
        sum_length[i] = sum_length[i - 1] + Length(i + L - 1) - Length(i);
      }
      for (int i = 0; i < m; ++i) {
        for (int j = i + 1; j < m; ++j) {
          if (sum[i] == sum[j]) {
            result = std::max(result, std::max(sum_length[i], sum_length[j]));
          }
        }
      }
    }
    return result;
  }

 private:
  int Gcd(int x, int y) { return y == 0 ? x : Gcd(y, x % y); }
};

code for problem2

#include <algorithm>
#include <vector>

class StoryFromTCO {
 public:
  int minimumChanges(const std::vector<int> &places,
                     const std::vector<int> &cutoff) {
    std::vector<std::pair<std::pair<int, int>, bool>> good;
    std::vector<int> bad_places;
    std::vector<int> bad_cutoff;
    for (size_t i = 0; i < places.size(); ++i) {
      if (places[i] <= cutoff[i]) {
        good.push_back({{places[i], cutoff[i]}, false});
      } else {
        bad_places.push_back(places[i]);
        bad_cutoff.push_back(cutoff[i]);
      }
    }
    auto Sort = [&](size_t idx) {
      std::sort(bad_places.begin() + idx, bad_places.end());
      std::sort(bad_cutoff.begin() + idx, bad_cutoff.end());
    };
    auto FindBest = [&](int cut) -> int {
      int n = static_cast<int>(good.size());
      int bst = -1;
      for (int i = 0; i < n; ++i) {
        if (!good[i].second && good[i].first.first <= cut &&
            (bst == -1 || good[bst].first.second < good[i].first.second)) {
          bst = i;
        }
      }
      return bst;
    };
    Sort(0);
    size_t idx = 0;
    while (idx < bad_places.size()) {
      if (bad_places[idx] <= bad_cutoff[idx]) {
        ++idx;
        continue;
      }
      int bst = FindBest(bad_cutoff[idx]);
      if (bst == -1) {
        return -1;
      }
      bad_places.push_back(good[bst].first.first);
      bad_cutoff.push_back(good[bst].first.second);
      good[bst].second = true;
      Sort(idx);
    }
    return static_cast<int>(bad_cutoff.size());
  }
};

code for problem3

#include <algorithm>
#include <vector>

constexpr int kMAXN = 100000;
constexpr int kMAXM = 400;
constexpr int kMod = 1000000009;

long long fact[kMAXN + kMAXM + 1];
long long fact_inv[kMAXN + kMAXM + 1];
long long fpow[kMAXM + 2];

int f[kMAXM / 2 + 1][kMAXM / 2 + 1][kMAXM + 1];

class ColourHolic {
 public:
  int countSequences(std::vector<int> all) {
    std::sort(all.begin(), all.end());
    Initialize(all[2] + all[3] + all[0] + all[1]);
    if (all[2] == 0) {
      if (all[3] > 1) {
        return 0;
      } else {
        return 1;
      }
    }
    if (all[1] == 0) {
      if (all[2] == all[3]) {
        return 2;
      } else if (all[2] + 1 == all[3]) {
        return 1;
      } else {
        return 0;
      }
    }

    auto Get = [&](int m, int mul) {
      long long r = Compute(m + 1, all[2], all[3]);
      r += Compute(m, all[2], all[3]) * 2;
      r += Compute(m - 1, all[2], all[3]);
      return static_cast<int>(r % kMod * mul % kMod);
    };

    if (all[0] == 0) {
      return Get(all[1], 1);
    }
    int n = all[0];
    int m = all[1];
    f[0][1][1] = 1;
    for (int i = 1; i <= n; ++i) {
      f[i][i][1] = 2;
      f[i][i - 1][1] = 1;
      if (i + 1 <= m) {
        f[i][i + 1][1] = 1;
      }
    }
    int result = Get(1, f[n][m][1]);
    for (int k = 2; k <= n + m; ++k) {
      for (int i = 0; i <= n; ++i) {
        int t = 1;
        while (t <= m && i + t <= n) {
          Add(f[i + t][t][k - 1], f[i + t - 1][t - 1][k - 1]);
          ++t;
        }
      }
      for (int j = 1; j <= m; ++j) {
        int t = 1;
        while (t <= n && j + t <= m) {
          Add(f[t][j + t][k - 1], f[t - 1][j + t - 1][k - 1]);
          ++t;
        }
      }
      for (int i = 0; i <= n; ++i) {
        for (int j = 0; j <= m; ++j) {
          if (i > 0 && j > 0) {
            Add(f[i][j][k], f[i - 1][j - 1][k - 1] * 2);
          }
          if (i > 0) {
            Add(f[i][j][k], f[i - 1][j][k - 1]);
          }
          if (j > 0) {
            Add(f[i][j][k], f[i][j - 1][k - 1]);
          }
        }
      }
      Add(result, Get(k, f[n][m][k]));
    }
    return result;
  }

 private:
  void Add(int &x, int y) {
    if (y >= kMod) {
      y -= kMod;
    }
    x += y;
    if (x >= kMod) {
      x -= kMod;
    }
  }

  long long Compute(int m, int a, int b) {
    if (m == 0) {
      return 0;
    }
    long long result = 0;
    for (int t = 0; t <= a && t <= m; ++t) {
      int p = b - a + t;
      int q = m - p - t;
      if (q < 0) {
        continue;
      }
      result += C(m, t) * C(m - t, p) % kMod * fpow[q] % kMod *
                C(a + p - 1, m - 1) % kMod;
    }
    return result % kMod;
  }

  void Initialize(int n) {
    fact[0] = fact_inv[0] = 1;
    fact[1] = fact_inv[1] = 1;
    for (int i = 2; i <= n; ++i) {
      fact[i] = fact[i - 1] * i % kMod;
      fact_inv[i] = GetInv(fact[i]);
    }
    fpow[0] = 1;
    for (int i = 1; i <= kMAXM + 1; ++i) {
      fpow[i] = fpow[i - 1] * 2 % kMod;
    }
  }

  long long C(int n, int m) {
    if (n < m || m < 0) {
      return 0;
    }
    return fact[n] * fact_inv[m] % kMod * fact_inv[n - m] % kMod;
  }

  long long GetInv(long long n) {
    int m = kMod - 2;
    long long r = 1;
    while (m != 0) {
      if ((m & 1) == 1) {
        r = r * n % kMod;
      }
      m >>= 1;
      n = n * n % kMod;
    }
    return r;
  }
};
相關文章
相關標籤/搜索