topcoder srm 605 div1

problem1 link數組

首先按照type分類,同一類若是都是負數,那麼取最大值,不然將全部的正數加起來做爲這個type的價值。而後就是二維的揹包。code

problem2 linkblog

從小到大將每一個數字分到A或者B集合。設$f[i][j][m]$表示已經分配完前$i$個數字,A集合中分配了$j$個數字,已經分配的前$i$個數字中的最大的$K$個數字(即$[i-K+1,i]$)在兩個集合中的分佈狀況爲$m$的劃分方案數。$m$是一個$K$位二進制數字。get

problem3 linkstring

設原來的數組爲$P$,最終的數組爲$S$.it

有兩個重要的性質:(1)$S$中的數字的先後順序與其在$P$中的先後順序是一致的,好比$P=[3,2,1,4,5]$不會使得$S=[2,3,1,4,5]$;(2)$S$中不會出現兩段相同的數字,好比$S=[3,2,3,4,5]$io

因此只須要挨個肯定$S$中的每一個數字,並記錄$S$中最後肯定的數字是$P$中的哪個便可。ast

設$f[i][j][k][t]$表示已經肯定好了$S$的前$i$個數字,其中$S[i]=P[j]$.而且已經使用了$k$次操做。$t$是一個tag(能夠取0或者1兩個值),它表示當用$j$去擴展到$i$時是否使用了一次操做。這個的意義在於若是後面還要用$P[j]$去擴展到$S[i+1]$,若是前面已經使用了一次操做,那麼後面的操做數就不用再加1了。class

code for problem1擴展

#include <limits>
#include <unordered_map>
#include <vector>

class AlienAndHamburgers {
 public:
  int getNumber(const std::vector<int> &type, const std::vector<int> &taste) {
    std::unordered_map<int, int> a;
    for (size_t i = 0; i < type.size(); ++i) {
      int t = type[i];
      int c = taste[i];
      if (a.find(t) == a.end()) {
        a[t] = c;
        continue;
      }
      if (c < 0) {
        if (a[t] < 0) {
          a[t] = std::max(a[t], c);
        }
      } else {
        a[t] = std::max(a[t] + c, c);
      }
    }
    int m = static_cast<int>(a.size());
    std::vector<std::vector<int>> f(
        m, std::vector<int>(m + 1, std::numeric_limits<int>::lowest()));
    int idx = 0;
    for (const auto &e : a) {
      int c = e.second;
      if (idx == 0) {
        f[0][0] = 0;
        f[0][1] = c;
        ++idx;
        continue;
      }
      for (int j = 0; j <= idx; ++j) {
        f[idx][j] = std::max(f[idx][j], f[idx - 1][j]);
        f[idx][j + 1] = std::max(f[idx][j + 1], f[idx - 1][j] + c);
      }
      ++idx;
    }
    int result = 0;
    for (int i = 1; i <= idx; ++i) {
      result = std::max(result, i * f[idx - 1][i]);
    }
    return result;
  }
};

code for problem2

#include <cmath>
#include <vector>

class AlienAndSetDiv1 {
  static constexpr int kMod = 1000000007;

 public:
  int getNumber(int N, int K) {
    std::vector<std::vector<std::vector<int>>> f(
        N + N + 1,
        std::vector<std::vector<int>>(N + 1, std::vector<int>(1 << K)));
    if (K >= N + N) {
      return AnySplit(N);
    }
    for (int i = 0; i < (1 << K); ++i) {
      std::vector<int> a, b;
      for (int j = 0; j < K; ++j) {
        if ((i & (1 << j)) == 0) {
          a.push_back(j + 1);
        } else {
          b.push_back(j + 1);
        }
      }
      bool tag = true;
      for (std::size_t j = 0; j < a.size() && j < b.size(); ++j) {
        if (std::abs(a[j] - b[j]) < K) {
          tag = false;
          break;
        }
      }
      if (tag) {
        f[K][a.size()][i] += 1;
      }
    }

    std::vector<int> bit_num(1 << K);
    for (int i = 1; i < (1 << K); ++i) {
      bit_num[i] = bit_num[i >> 1] + (i & 1);
    }
    std::vector<std::vector<int>> indices0(1 << K, std::vector<int>(K + 1));
    std::vector<std::vector<int>> indices1(1 << K, std::vector<int>(K + 1));
    for (int i = 0; i < (1 << K); ++i) {
      int num0 = 0;
      int num1 = 0;
      for (int j = 0; j < K; ++j) {
        if ((i & (1 << j)) == 0) {
          ++num0;
          indices0[i][num0] = j;
        } else {
          ++num1;
          indices1[i][num1] = j;
        }
      }
    }
    for (int i = K + 1; i <= N + N; ++i) {
      for (int a = 0; a < i && a <= N; ++a) {
        int b = i - 1 - a;
        for (int k = 0; k < (1 << K); ++k) {
          if (f[i - 1][a][k] != 0) {
            if (a + 1 <= N) {
              if (a >= b) {
                (f[i][a + 1][k >> 1] += f[i - 1][a][k]) %= kMod;
              } else {
                int t = bit_num[k];
                if ((t < b - a) || (indices1[k][t - (b - a) + 1] == 0)) {
                  (f[i][a + 1][k >> 1] += f[i - 1][a][k]) %= kMod;
                }
              }
            }
            if (b + 1 <= N) {
              if (a <= b) {
                (f[i][a][(k >> 1) | (1 << (K - 1))] += f[i - 1][a][k]) %= kMod;
              } else {
                int t = K - bit_num[k];
                if ((t < a - b) || (indices0[k][t - (a - b) + 1] == 0)) {
                  (f[i][a][(k >> 1) | (1 << (K - 1))] += f[i - 1][a][k]) %=
                      kMod;
                }
              }
            }
          }
        }
      }
    }
    int result = 0;
    for (int i = 0; i < (1 << K); ++i) {
      (result += f[N + N][N][i]) %= kMod;
    }
    return result;
  }

 private:
  int AnySplit(int n) {
    std::vector<std::vector<int>> c(2 * n + 1, std::vector<int>(2 * n + 1, 0));
    c[0][0] = c[1][0] = c[1][1] = 1;
    for (int i = 2; i <= 2 * n; ++i) {
      c[i][0] = c[i][i] = 1;
      for (int j = 1; j < i; ++j) {
        c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % kMod;
      }
    }
    return c[n + n][n];
  }
};

code for problem3

#include <vector>
#include <cstring>

int f[200][200][201][2];

class AlienAndPermutation {
 public:
  int getNumber(const std::vector<int> &P, int K) {
    if (K == 0) {
      return 1;
    }
    int n = static_cast<int>(P.size());
    std::vector<std::vector<bool>> tag(n, std::vector<bool>(n, true));
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < n; ++j) {
        for (int k = std::min(i, j), stop = std::max(i, j); k <= stop; ++k) {
          if (P[k] > P[i]) {
            tag[i][j] = false;
            break;
          }
        }
      }
    }
    memset(f, -1, sizeof(f));
    return dfs(0, 0, K, 0, n, tag);
  }

 private:
  int dfs(int i, int j, int k, int t, int n,
          const std::vector<std::vector<bool>> &tag) {
    constexpr int kMod = 1000000007;
    if (k < 0) {
      return 0;
    }
    if (j == n) {
      return 1;
    }
    if (i == n) {
      return 0;
    }
    int &result = f[i][j][k][t];
    if (result != -1) {
      return result;
    }
    result = dfs(i + 1, j, k, 0, n, tag);
    if (tag[i][j]) {
      int new_k = k - ((i != j && t == 0) ? 1 : 0);
      int new_t = (t != 0 || i != j) ? 1 : 0;
      (result += dfs(i, j + 1, new_k, new_t, n, tag)) %= kMod;
    }
    return result;
  }
};
相關文章
相關標籤/搜索