topcoder srm 565 div1

problem1 link

$f[i][j]$表示经过前$i$个怪物之后,花费$j$个硬币可以得到的最大值。

problem2 link

设$nim[i]$表示数字$i$的nim值。那么题目就是求有多少个区间$[L,R]$满足这个区间内所有数字的nim值的抑或不是0.通过记录前缀和的个数,可以$O(n)$计算得到。现在问题是计算每个值的nim值。

可以用数学归纳法证明$i$的nim值等于$i$中的质因子的个数,比如$nim[6]=2,nim[12]=3$等。所以对于给出的的区间$[L,R]$,只需要枚举$\sqrt{R}$之内的质数,判断$[L,R]$内哪些数字的质因子有该质数。

假设需要考虑的所有质数为$p_{1},p_{2},...,p_{m},n=R-L+1$,那么复杂度为$\sum_{i=1}^{m}\frac{n}{p_{i}}$

problem3 link

(1)首先考虑只有一个特殊点$A$,假设$A$为树根,那么只需要为每个点找到一个父节点即可,对于节点$i$来说,如果$j$满足$dist[i]<dist[j]$,那么$j$可以作为$i$的父节点。所以如果令$f[i]$表示可以作为$i$的父节点的节点数,那么答案为$\prod_{i=1}^{n}(1+f(i))$

(2)考虑有两个特殊点$A,B$,假设$B$为树根,令$i$为$AB$之间距离$B$最近的节点($i$有可能就是A),那么将从$i$开始以及A的子节点这些都叫做$A$分支,其他的除了$B$以外的节点都叫做其他分支。令$AB$之间的长度为$p$.那么一个节点$j$满足$dist[A]-dist[B]=p$时,它就在其他分支上,否则就在A分支上。那么其他分支其实就是一个特殊点的问题,而A分支可以看做$i$节点是新的$B$的两个特殊点的问题。

(3)现在考虑三个特殊点$ABC$。分两种情况:第一,存在一个节点$i$使得ABC在以$i$为根的三个分支上。现在所有除了$i$以外的点,要么在A,B,C中的一个分支上,要么在之外的分支上。比如,如果一个点$j$满足$A[j]-A[i]=B[j]-B[i]=C[j]-C[i]$,那么它就在其他分支上,如果$A[j]-A[i]=B[j]-B[i]\neq C[j]-C[i]$,那么它就在C分支上。这样其他分支上就是一个特殊点的问题,而A分支,B分支,C分支就是三个两个特殊点的问题($i$是两个特殊点问题中的$B$); 第二,如果ABC是一条链上的三个点,假设B在中间,那么现在B作为树根,每个节点要么在A分支,要么在C分支,要么在其他分支。这里需要首先确定AB和BC的长度,这里可以枚举节点$i$在其他分支,AB中间,BC之间,A分支上但是不是AB之间等情况来确定AB和BC的长度,这样就又转化成一个特殊点和两个特殊点的问题。

code for problem1

#include <vector>

class MonstersValley {
 public:
  int minimumPrice(std::vector<long long> dread, std::vector<int> price) {
    const int n = static_cast<int>(dread.size());
    std::vector<std::vector<long long>> f(
        n + 1, std::vector<long long>(n * 2 + 1, -1));
    f[0][0] = 0;
    for (int i = 1; i <= n; ++i) {
      long long t = dread[i - 1];
      int c = price[i - 1];
      for (int j = 0; j <= 2 * i; ++j) {
        if (f[i - 1][j] != -1) {
          f[i][j + c] = std::max(f[i][j + c], f[i - 1][j] + t);
          if (f[i - 1][j] >= t) {
            f[i][j] = std::max(f[i][j], f[i - 1][j]);
          }
        }
      }
    }
    for (int i = 0; i <= n * 2; ++i) {
      if (f[n][i] != -1) {
        return i;
      }
    }
    return 0;
  }
};

code for problem2

#include <chrono>
#include <cmath>
#include <iostream>
#include <vector>

class TheDivisionGame {
 public:
  long long countWinningIntervals(int L, int R) {
    std::vector<int> prime = ComputePrime(static_cast<int>(std::sqrt(R)) + 1);
    int n = R - L + 1;
    std::vector<int> value(n);
    std::vector<int> nim(n, 0);
    for (int i = 0; i < n; ++i) {
      value[i] = i + L;
    }
    for (size_t i = 0; i < prime.size() && prime[i] * prime[i] <= R; ++i) {
      int s = L;
      if (L % prime[i] != 0) {
        s += prime[i] - L % prime[i];
      }
      while (s <= R) {
        while (value[s - L] % prime[i] == 0) {
          value[s - L] /= prime[i];
          nim[s - L] += 1;
        }
        s += prime[i];
      }
    }
    for (int i = 0; i < n; ++i) {
      if (value[i] != 1) {
        ++nim[i];
      }
    }
    std::vector<int> num(32, 0);
    num[0] = 1;
    long long result = 0;
    for (int i = 0, prefix = 0; i < n; ++i) {
      prefix ^= nim[i];
      result += i + 1 - num[prefix];
      num[prefix] += 1;
    }
    return result;
  }

 private:
  std::vector<int> ComputePrime(int M) {
    std::vector<int> prime;
    std::vector<bool> tag(M + 1, false);
    for (int i = 2; i <= M; ++i) {
      if (!tag[i]) {
        prime.push_back(i);
      }
      for (size_t j = 0; j < prime.size() && prime[j] * i <= M; ++j) {
        tag[prime[j] * i] = true;
        if (i % prime[j] == 0) {
          break;
        }
      }
    }
    return prime;
  }
};

code for problem3

#include <algorithm>
#include <iostream>
#include <set>
#include <vector>

class UnknownTree {
  static constexpr int mod = 1000000009;

 public:
  int getCount(std::vector<int> distancesA, std::vector<int> distancesB,
               std::vector<int> distancesC) {
    int result = 0;
    for (int i = 0; i < static_cast<int>(distancesA.size()); ++i) {
      Add(result, Compute(i, distancesA, distancesB, distancesC));
    }
    Add(result, ComputeLine(distancesA, distancesB, distancesC));
    Add(result, ComputeLine(distancesB, distancesA, distancesC));
    Add(result, ComputeLine(distancesA, distancesC, distancesB));
    return result;
  }

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

  int Compute(int root, const std::vector<int> &A, const std::vector<int> &B,
              const std::vector<int> &C) {
    std::vector<int> other, set_a, set_b, set_c;
    std::vector<int> set_a_root, set_b_root, set_c_root;
    int n = static_cast<int>(A.size());
    for (int i = 0; i < n; ++i) {
      if (i != root) {
        int da = A[i] - A[root];
        int db = B[i] - B[root];
        int dc = C[i] - C[root];
        if (da > 0 && da == db && da == dc) {
          other.push_back(da);
        } else if (da > 0 && da == db) {
          set_c.push_back(C[i]);
          set_c_root.push_back(da);
        } else if (da > 0 && da == dc) {
          set_b.push_back(B[i]);
          set_b_root.push_back(da);
        } else if (db > 0 && db == dc) {
          set_a.push_back(A[i]);
          set_a_root.push_back(db);
        } else {
          return 0;
        }
      }
    }
    long long result = SolveCase1(other);
    result = result * SolveCase2(A[root], set_a_root, set_a) % mod;
    result = result * SolveCase2(B[root], set_b_root, set_b) % mod;
    result = result * SolveCase2(C[root], set_c_root, set_c) % mod;
    return static_cast<int>(result);
  }

  int ComputeLine(const std::vector<int> &A, const std::vector<int> &B,
                  const std::vector<int> &C) {
    std::set<std::pair<int, int>> all;
    auto Insert = [&](int ab, int bc) {
      if (ab > 0 && bc > 0) {
        all.insert({ab, bc});
      }
    };
    int n = static_cast<int>(A.size());
    for (int i = 0; i < n; ++i) {
      Insert(A[i] - B[i], C[i] - B[i]);
      Insert(A[i] + B[i], C[i] - B[i]);
      Insert(B[i] - A[i], C[i] - B[i]);
      Insert(A[i] - B[i], B[i] + C[i]);
      Insert(A[i] - B[i], B[i] - C[i]);
    }
    int result = 0;
    for (auto &e : all) {
      Add(result, ComputeLine(e.first, e.second, A, B, C));
    }
    return result;
  }

  int ComputeLine(int ab, int bc, const std::vector<int> &A,
                  const std::vector<int> &B, const std::vector<int> &C) {
    int n = static_cast<int>(A.size());
    std::vector<int> other, set_a, set_c;
    std::vector<int> set_a_b, set_c_b;
    for (int i = 0; i < n; ++i) {
      if (A[i] - B[i] == ab && C[i] - B[i] == bc) {
        other.push_back(B[i]);
      } else if (A[i] - B[i] == ab && OnLater(bc, B[i], C[i])) {
        set_c.push_back(C[i]);
        set_c_b.push_back(B[i]);
      } else if (C[i] - B[i] == bc && OnLater(ab, B[i], A[i])) {
        set_a.push_back(A[i]);
        set_a_b.push_back(B[i]);
      } else {
        return 0;
      }
    }
    long long result = SolveCase1(other);
    result = result * SolveCase2(ab, set_a_b, set_a) % mod;
    result = result * SolveCase2(bc, set_c_b, set_c) % mod;
    return static_cast<int>(result);
  }

  bool OnLater(int d, int da, int db) {
    return (da + db == d) || (da - db == d) || (d > 1 && da + db > d);
  }

  int SolveCase1(const std::vector<int> &d) {
    int n = static_cast<int>(d.size());
    long long result = 1;
    for (int i = 0; i < n; ++i) {
      int t = 1;
      for (int j = 0; j < n; ++j) {
        if (j != i && d[j] < d[i]) {
          ++t;
        }
      }
      result = result * t % mod;
    }
    return static_cast<int>(result);
  }
  int SolveCase2(int ab, const std::vector<int> &B, std::vector<int> &A) {
    int n = static_cast<int>(B.size());
    if (n == 0) {
      return 1;
    }
    std::vector<int> set_b, set_a_middle, set_a_other;
    int middle_branch = 0;
    for (int i = 0; i < n; ++i) {
      if (B[i] + ab == A[i]) {
        set_b.push_back(B[i]);
      } else {
        if (B[i] + A[i] < ab) {
          return 0;
        } else if (B[i] + A[i] == ab) {
          set_a_middle.push_back(B[i]);
        } else if (B[i] - A[i] == ab) {
          set_a_other.push_back(A[i]);
        } else if (B[i] + A[i] > ab) {
          ++middle_branch;
        } else {
          return 0;
        }
      }
    }
    long long result = SolveCase1(set_b);
    if (set_a_middle.size() == 0) {
      if (middle_branch != 0) {
        return 0;
      }
      result = result * SolveCase1(set_a_other) % mod;
      return static_cast<int>(result);
    }
    std::sort(set_a_middle.begin(), set_a_middle.end());
    int m = static_cast<int>(set_a_middle.size());
    for (int i = 0; i + 1 < m; ++i) {
      if (set_a_middle[i] == set_a_middle[i + 1]) {
        return 0;
      }
    }
    int delta = set_a_middle[0];
    if (delta >= ab) {
      return 0;
    }
    std::vector<int> d_set_a, d_set_b;
    for (int i = 0; i < n; ++i) {
      if (B[i] + ab != A[i]) {
        if (B[i] + A[i] == ab) {
          if (B[i] != delta) {
            d_set_b.push_back(B[i] - delta);
            d_set_a.push_back(A[i]);
          }
        } else {
          if (B[i] <= delta) {
            return 0;
          }
          d_set_b.push_back(B[i] - delta);
          d_set_a.push_back(A[i]);
        }
      }
    }
    result = result * SolveCase2(ab - delta, d_set_b, d_set_a) % mod;
    return static_cast<int>(result);
  }
};

  

原文地址:https://www.cnblogs.com/jianglangcaijin/p/9043276.html

时间: 2024-10-11 19:30:06

topcoder srm 565 div1的相关文章

Topcoder SRM 643 Div1 250&lt;peter_pan&gt;

Topcoder SRM 643 Div1 250 Problem 给一个整数N,再给一个vector<long long>v; N可以表示成若干个素数的乘积,N=p0*p1*p2*......*pn,我们假设p0,p1,...,pn是单调不降的,那么v里存储的是下标为偶数 的N的质因数p0,p2,p4,...,p(2k).现在要求写一个程序,返回一个vector<long long>ans; ans里存储的是p0,p1,p2,...,pn. Limits Time Limit(m

Topcoder SRM 648 Div1 250

Problem 给一个长度为N的"AB"字符串S,S只含有两种字符'A' 或 'B',设pair(i,j)(0=<i<j<N)表示一对 i,j 使得S[i]='A',S[j]='B'.现给定一个K,求字符串S,使得pair(i,j)的个数恰好为K.若不存在,则返回空串. Limits Time Limit(ms): 2000 Memory Limit(MB): 256 N: [2, 50] K: [0 , N*(N-1)/2 ] Solution 若K>(N/2

Topcoder SRM 627 div1 HappyLettersDiv1 : 字符串

Problem Statement      The Happy Letter game is played as follows: At the beginning, several players enter the field. Each player has a lowercase English letter on their back. The game is played in turns. In each turn, you select two players with dif

topcoder srm 738 div1 FindThePerfectTriangle(枚举)

Problem Statement      You are given the ints perimeter and area. Your task is to find a triangle with the following properties: The coordinates of each vertex are integers between 0 and 3000, inclusive. The perimeter of the triangle must be exactly

Topcoder SRM 603 div1题解

昨天刚打了一场codeforces...困死了...不过赶在睡前终于做完了- 话说这好像是我第一次做250-500-1000的标配耶--- Easy(250pts): 题目大意:有一棵树,一共n个节点,每个节点都有一个权值,两人A和B分别进行操作,由A先手,每人可以选择一条边,将它删掉得到两个联通块.游戏不断进行下去,最后只剩下一个节点.A希望最后的节点权值尽可能大,B希望尽可能小,求这个最后的值.数据保证n<=50. 这道题真的是博弈好题啊-(感觉放到ACM很合适啊) 我们考虑第一次A会如何选

topcoder srm 320 div1

problem1 link 两个数字后面都有阶乘符号,可以抵消. import java.util.*; import java.math.*; import static java.lang.Math.*; public class ExtraordinarilyLarge { public String compare(String x, String y) { boolean both=false; while(x.endsWith("!")&&y.endsWit

topcoder srm 712 div1 -23

1.给定两个长度为$n$的数组$A,B$.有两种操作可以作用于数组$A$.第一种,将每个元素左侧的相邻数字加到其上:第二种,将每个元素右侧的相邻数字加到其上.0的左侧是$n-1$,$n-1$的右侧是0.比如1,2,3,4执行第一种操作后是5,3,5,7.给出一个不超过100的操作序列使得$A$变成$B$.$n \leq 50$. 思路:将$a_{0},a_{1},...,a_{n-1}$看做$a_{0}x^{0}+a_{1}x^{1}+...+a_{n-1}x^{n-1}$.那么第一种操作相当于

Topcoder SRM 345 Div1 250

题意:起初在(0,0),要到(x,y)去,每次只能横向或纵向移动.横向移动时,若所在直线y为偶数,那么只能往x轴正方向移动,若为奇数,只能往x轴反方向移动:纵向移动时,若所在直线x为偶数,那么只能往y轴正方向移动,若为奇数,只能往y轴反方向移动.问从起点到终点的最短距离是多少? x,y 范围是[-1e6, 1e6] 解法:一开始想到bfs(想到很自然),将(0, 0), (x, y), (x, 0), (0, y)这4个点分别周围9个点(包括自己)作为可达点.bfs处理出(0, 0)到(x, y

Topcoder SRM 653 Div1 250

Problem N个人坐成一排,属于同一个公司的人都坐在一起(挨在一起),但不知道谁属于哪个公司.现在问其中的某些人 他属于哪个公司,他的回答是Ai,Ai=0表示此人未被询问,否则表示他的回答.题目保证一定存在一种分组方案使得属于同一公司的人都坐在一起.现问方案是否唯一? Limits TimeLimit(ms):2000 MemoryLimit(MB):256 N,Ai∈[1,100] Solution 设dp[i]表示从i位置开始往后分组的情况,dp[i]=0表示无法分组,dp[i]=1表示