topcoder srm 585 div1

problem1 link

最优的策略就是从最低下一层开始,每两层的三个节点的子树都可以用一次遍历覆盖。

problem2 link

从大到小依次放置每一种数字,并记录已经放置的数字一共有多少个$m$以及有多少个严格的升序列$K$。那个如果新放置的一个数字(必然小于序列中所有的数字)放在了升序列的开头,那么升序列个数不变;否则升序列的个数增加1.所以有$K$个位置可以使得升序列个数不变,而有$n+1-K$个位置使得升序列个数增加1.现在考虑新放置的数字有多个的情况。假设新放置的数字有$n$个,首先将他们插入到原来的序列前现将其分为$t$组,要求每一组插入的时候是连续的。那么每一组中前面的数字必定是有几个就会使得升序列个数增加几个,即一定至少增加$n-t$.那么如果$t$组中选择$x$组放在之前增序列的开头,剩下的$t-x$组放在其他位置,那么增加的增序列的总个数为$(n-t)+(t-x)$,方案数为$C_{K}^{x}C_{m+1-K}^{t-x}$.

problem3 link

首先将边上的$4m$个点按照顺时针看作一个序列,那么对于序列中的每个点$i$可以计算一个$left[i],right[i]$。$left[i]$表示在$i$前面最远的点满足那个点与$i$点的连线使得所有内部的点都在这条线上或者右侧。$right[i]$含义类似。

现在枚举每个点作为$a$作为三角形的一个顶点,其他两个顶点设为$b,c$。那么$b,c$一定要满足$left[a]\leq c\leq right[b],left[c]\leq b\leq right[a]$.

所以如果$b$也一旦确定,那么$c$的可选个数为$right[b]-left[a]+1$,所以当$a$确定时的答案为$f(a)=\sum_{b=left[left[a]]}^{right[a]}right[b]-left[a]+1$

特殊情况是如果$left[left[a]]$跟 $a$是同一个点的时候,这时候$b$的取值是$[a+1, right[a]]$,即便这样$f(a)=\sum_{b=a+1}^{right[a]}right[b]-left[a]+1$还是多算了两个不合法的三角形,它们是 $(a,left[a],left[a])$以及$(a,left[a],a)$

 

code for problem1

#include <stdint.h>

class TrafficCongestion {
  static constexpr int kMod = 1000000007;

 public:
  int theMinCars(int treeHeight) {
    int result = 0;
    while (treeHeight >= 0) {
      if (treeHeight <= 1) {
        result = (result + 1) % kMod;
        break;
      } else {
        result += Pow(treeHeight - 1);
        result %= kMod;
        treeHeight -= 2;
      }
    }
    return result;
  }

 private:
  static int Pow(int k) {
    int64_t result = 1;
    int64_t a = 2;
    while (k > 0) {
      if ((k & 1) == 1) {
        result = result * a % kMod;
      }
      a = a * a % kMod;
      k >>= 1;
    }
    return static_cast<int>(result);
  }
};

code for problem2

#include <stdint.h>
#include <cstring>
#include <vector>

class LISNumber {
  static constexpr int64_t kMod = 1000000007;
  static constexpr int64_t kMax = 36;

 public:
  int count(const std::vector<int> &cards, int K) {
    if (K < cards.back()) {
      return 0;
    }
    int N = 0;
    for (auto e : cards) {
      N += e;
    }
    if (K > N) {
      return 0;
    }

    Initialize();

    std::vector<int> f0(K + 1, 0);
    std::vector<int> f1(K + 1, 0);
    f0[cards.back()] = 1;
    int m = cards.back();
    for (int i = static_cast<int>(cards.size()) - 2; i >= 0; --i) {
      int n = cards[i];
      for (auto &e : f1) {
        e = 0;
      }
      for (int k = 1; k <= K; ++k) {
        if (f0[k] == 0) {
          continue;
        }
        for (int t = 1; t <= n; ++t) {
          auto b = static_cast<int64_t>(f0[k]) * split_[n][t] % kMod;
          int delta_k = n - t;
          for (int x = 0; x <= t && x + delta_k + k <= K; ++x) {
            int b1 = static_cast<int>(b * c_[k][t - x] % kMod *
                                      c_[m - k + 1][x] % kMod);
            (f1[x + delta_k + k] += b1) %= kMod;
          }
        }
      }
      m += n;
      f0 = f1;
    }
    return f0[K];
  }

 private:
  void Initialize() {
    c_[0][0] = 1;
    for (int i = 1; i <= kMax; ++i) {
      c_[0][i] = 0;
    }
    for (int i = 1, end = kMax * kMax; i <= end; ++i) {
      c_[i][0] = 1;
      for (int j = 1; j <= kMax; ++j) {
        c_[i][j] = (c_[i - 1][j] + c_[i - 1][j - 1]) % kMod;
      }
    }
    memset(split_, 0, sizeof(split_));
    std::vector<std::pair<int, int>> p;
    for (int i = 1; i <= kMax; ++i) {
      p.push_back({i, 1});
      Dfs(1, i, i, &p);
      p.clear();
    }
  }

  void Dfs(int depth, int begin, int sum, std::vector<std::pair<int, int>> *p) {
    if (sum > kMax) {
      return;
    }
    {
      int64_t x = 1;
      int n = depth;
      for (size_t i = 0; i < p->size(); ++i) {
        (x *= c_[n][(*p)[i].second]) %= kMod;
        n -= (*p)[i].second;
      }
      (split_[sum][depth] += static_cast<int>(x)) %= kMod;
    }
    for (int i = begin, end = kMax - sum; i <= end; ++i) {
      if (p->back().first == i) {
        p->back().second += 1;
      } else {
        p->push_back({i, 1});
      }
      Dfs(depth + 1, i, sum + i, p);

      if (p->back().second > 1) {
        p->back().second -= 1;
      } else {
        p->pop_back();
      }
    }
  }

  int c_[kMax * kMax + 1][kMax + 1];
  int split_[kMax + 1][kMax + 1];
};

code for problem3

#include <unistd.h>
#include <algorithm>
#include <vector>

class EnclosingTriangle {
 public:
  long long getNumber(int m, const std::vector<int>& x,
                      const std::vector<int>& y) {
    const int n = m << 2;
    std::vector<std::pair<int, int>> all(3 * n);
    std::vector<int> left(3 * n);
    std::vector<int> right(3 * n);
    std::vector<long long> prefix(3 * n);
    {
      int idx = 0;
      auto Add = [&](int x0, int y0, int x1, int y1) {
        int dx = x1 >= x0 ? 1 : -1;
        int dy = y1 >= y0 ? 1 : -1;
        int x_num = abs(x1 - x0) + 1;
        int y_num = abs(y1 - y0) + 1;
        for (int i = 0; i < x_num; ++i) {
          for (int j = 0; j < y_num; ++j) {
            all[idx] = all[idx + n] = all[idx + n + n] =
                std::make_pair(i * dx + x0, j * dy + y0);
            ++idx;
          }
        }
      };
      Add(0, 0, 0, m - 1);
      Add(0, m, m - 1, m);
      Add(m, m, m, 1);
      Add(m, 0, 1, 0);
    }
    {
      auto Check = [&](const std::pair<int, int>& p1,
                       const std::pair<int, int>& p2) {
        long long dx1 = p2.first - p1.first;
        long long dy1 = p2.second - p1.second;
        for (size_t i = 0; i < x.size(); ++i) {
          int dx2 = x[i] - p1.first;
          int dy2 = y[i] - p1.second;
          if (dx1 * dy2 - dy1 * dx2 > 0) {
            return false;
          }
        }
        return true;
      };
      for (int i = n; i < n + n; ++i) {
        {
          int low = i - n + 1;
          int up = i - 1;
          int result = up;
          while (low <= up) {
            int mid = (low + up) >> 1;
            if (Check(all[mid], all[i])) {
              result = std::min(result, mid);
              up = mid - 1;
            } else {
              low = mid + 1;
            }
          }
          left[i - n] = left[i] = left[i + n] = i - result;
        }
        {
          int low = i + 1;
          int up = i + n - 1;
          int result = low;
          while (low <= up) {
            int mid = (low + up) >> 1;
            if (Check(all[i], all[mid])) {
              result = std::max(result, mid);
              low = mid + 1;
            } else {
              up = mid - 1;
            }
          }
          right[i - n] = right[i] = right[i + n] = result - i;
        }
      }
      prefix[0] = right[0];
      for (int i = 1; i < n + n + n; ++i) {
        prefix[i] = prefix[i - 1] + right[i];
      }
    }
    long long result = 0;
    for (int a = n; a < n + n; ++a) {
      int c = a - left[a];
      int b_left = std::max(c - left[c] + n, a + 1);
      int b_right = a + right[a];
      if (b_right < b_left) {
        continue;
      }
      result += prefix[b_right] - prefix[b_left - 1];
      result -= static_cast<long long>(b_right - b_left + 1) *
                (c + n - b_left - 1 + c + n - b_right - 1) / 2;
      if (c + n == b_right) {
        // (a, c, c) and (a, c, a) are invalid.
        result -= 2;
      }
    }
    return result / 3;
  }
};

  

转载于:https://www.cnblogs.com/jianglangcaijin/p/9312206.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值