topcoder srm 714 div1

problem1 link

倒着想。每次添加一个右括号再添加一个左括号,直到还原。那么每次的右括号的选择范围为当前左括号后面的右括号减去后面已经使用的右括号。

problem2 link

令$h(x)=\sum_{i=1}^{x}g(i)$,那么答案为$h(R)-h(L-1)$。对于$h(x)$:

(1)如果$x\leq K$,那么$h(x)=0$

(2)否则对于$[K+1,x]$之间的所有偶数来说,对答案的贡献为$even+h(\frac{x}{2})-h(\frac{K}{2})$,其中$even=\frac{x}{2}-\frac{K}{2}$,$h(\frac{K}{2})=0$。奇数对答案的贡献为$odd*2+h(\frac{x+K}{2})$,$odd=x-K-even$。其中$[\frac{x}{2}+1,\frac{x+K}{2}]$之间的数字并不多,可以暴力。

problem3 link

下面第二个链接有关于714-div2-hard的题目的线形解法。它的思路记录过往的supply剩余总和以及demand的总和(如果supply大于 demand就抵消)。同时如果demand大于0还要记录最早的demand需要的位置。这样当出现新的supply并且足够抵消过去的demand时就回退回去满足demand然后返回。直到最后。

这道题与上面的区别是坐标会有负数并且可以在任意地方停止。所以可以假设先到达最左侧的某个地方,然后就跟上面类似了。对于在任何地方停止,可以贪心地计算。具体实现细节看代码以及注释。

 

code for problem1

#include <string>

class ParenthesisRemoval {
 public:
  int countWays(const std::string &s) {
    constexpr int kMod = 1000000007;
    int n = static_cast<int>(s.size());
    long long ans = 1;
    for (int i = n - 1, t = 0; i >= 0; --i) {
      if (s[i] == ')') {
        ++t;
      } else {
        ans = ans * t % kMod;
        --t;
      }
    }
    return ans;
  }
};

code for problem2

class NAddOdd {
 public:
  long long solve(long long L, long long R, int K) {
    return Dfs(R, K) - Dfs(L - 1, K);
  }

 private:
  long long g(long long x, int K) {
    long long ans = 0;
    while (x > K) {
      ++ans;
      if (x % 2 == 1) {
        x += K;
      } else {
        x >>= 1;
      }
    }
    return ans;
  }
  long long Dfs(long long x, int k) {
    if (x <= k) {
      return 0;
    }

    long long even = (x >> 1) - (k >> 1);
    long long odd = x - k - even;
    long long ans = even + (odd << 1) + (Dfs(x >> 1, k) << 1);
    for (long long i = (x >> 1) + 1; i <= ((x + k) >> 1); ++i) {
      ans += g(i, k);
    }
    return ans;
  }
};

code for problem3

#include <algorithm>
#include <vector>

class Salesman {
 public:
  int minMoves(std::vector<int> pos, std::vector<int> delta) {
    int result = Compute(pos, delta);
    std::reverse(pos.begin(), pos.end());
    std::reverse(delta.begin(), delta.end());
    for (auto &x : pos) {
      x *= -1;
    }
    result = std::min(result, Compute(pos, delta));
    return result;
  }

 private:
  int Compute(const std::vector<int> &pos, const std::vector<int> &delta) {
    int n = static_cast<int>(pos.size());
    int last_need = n - 1;
    while (last_need >= 0 && delta[last_need] >= 0) {
      --last_need;
    }
    if (last_need < 0) {
      return 0;
    }
    std::vector<int> next_need(n + 1, n);
    for (int i = n - 1; i >= 0; --i) {
      if (delta[i] < 0) {
        next_need[i] = i;
      } else {
        next_need[i] = next_need[i + 1];
      }
    }
    int result = std::numeric_limits<int>::max();
    for (int left = 0; left < n; ++left) {
      int right = last_need;
      int sum = 0;
      for (int i = left; i <= right; ++i) {
        sum += delta[i];
      }
      while (sum < 0 && right + 1 < n) {
        sum += delta[++right];
      }
      if (sum < 0) {
        break;
      }
      // The left is start and must visit right to get all supplys.
      int length = std::abs(pos[left]) + pos[right] - pos[left];
      int supply = 0;
      int demand = 0;
      int go_back_pos = 0;
      for (int i = left; i <= right; ++i) {
        if (delta[i] < 0) {
          int curr_demand = -delta[i];
          if (demand == 0 && supply >= curr_demand) {
            supply -= curr_demand;
          } else {
            if (demand == 0) {
              // If the pos[i] is negative, then just keep go_back_pos as
              // origin and need goto right and back to pos[i]
              go_back_pos = std::max(go_back_pos, pos[i]);
            }
            demand += curr_demand;
          }
        } else {
          supply += delta[i];
          if (demand > 0 && supply >= demand) {
            supply -= demand;
            demand = 0;
            // Here you have a choose that return to previous demand pos
            // immediately and back and in future you will no need to return
            // back
            length += 2 * std::max(0, pos[i] - go_back_pos);
          }
        }
        int final_stop_pos =
            demand > 0 ? go_back_pos : pos[std::min(right, next_need[i + 1])];
        result =
            std::min(result, length + std::max(0, pos[right] - final_stop_pos));
      }
      if (delta[left] < 0) {
        break;
      }
    }
    return result;
  }
};

  

参考:

https://codeforces.com/blog/entry/50602

https://www.topcoder.com/blog/single-round-match-714-editorials/

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值