首页 > 其他分享 >AtCoder Beginner Contest 280

AtCoder Beginner Contest 280

时间:2022-12-04 20:15:47浏览次数:75  
标签:std AtCoder hira Beginner int p2 280 include mint

D - Factorial and Multiple

对 \(k\) 进行质因数分解。

如果 \(k\) 最大的质因子 \(p\) 满足 \(p * p > k\) ,那么答案就是 \(p\)。因为一定要包含一次,也只需要包含一次。

否则直接爆搜。

AC代码
// #define MULTIPLE_TASK
#include "hira/main.cpp"

#include "hira/math/prime/pollard_rho.h"

void Initialize() {}

void SolveCase(int Case) {
  i64 k;
  std::cin >> k;

  auto p = math::Factor(k);
  logd(p);
  if (p.back() > 10'000'000) {
    std::cout << p.back() << "\n";
  } else {
    for (int i = 1;; ++i) {
      int g = std::gcd(i, k);
      k /= g;
      if (k == 1) {
        std::cout << i << "\n";
        break;
      }
    }
  }
}

E - Critical Hit

枚举用了 \(i\) 个 \(-1\),那么用了多少个 \(-2\) 也就能算出来了,记用了 \(j\) 个 \(-2\) 。

然后,如果 \(i + 2j > n\) ,说明最后一个操作为 \(2\) ,否则最后一个操作任意。

然后就是算一下概率,然后套期望公式了。

递推的做法:\(f(0) = 0, f(1) = 1, f(i) = pf(i - 2) + qf(i-1) + 1\)。

AC代码
// #define MULTIPLE_TASK
#include "hira/main.cpp"

#include "hira/math/modular/binom.h"
#include "hira/math/modular/mod_int.h"

using mint = math::ModInt998;
const auto binom = math::binom<mint>;

void Initialize() {}

void SolveCase(int Case) {
  int n, v;
  std::cin >> n >> v;

  mint p = mint(100 - v) / 100, q = mint(v) / 100;

  mint ans = 0;
  for (int i = 0; i <= n; ++i) {
    int j = (n - i + 1) / 2;

    if (i + 2 * j > n)
      ans += mint(i + j) * p.power(i) * q.power(j) * binom(i + j - 1, i);
    else
      ans += mint(i + j) * p.power(i) * q.power(j) * binom(i + j, i);

    logd(i, j, ans);
  }

  std::cout << ans.value() << "\n";
}

F - Pay or Receive

如果不属于同一连通块,就是 nan ,这个可以用并查集搞。

否则,如果该连通块有权非零的环,则 inf,正环就不解释了,在本题中负环反着跑就是正环。这个的判断可以跑遍 DFS。

现在需要回答多源多汇最长路的询问,普适的算法必定超时,所以要根据题目条件进一步优化。

现在没有权非零的环了,任意两点间的距离是唯一的,因为如果不唯一就能推出有权非零的环。

所以可以转成树上的两点间距离询问,经典。

还可以进一步优化:对于任意两点,\(d(x, y) = -d(y,x)\) ,假设以 \(r\) 为根跑出 DFS 树,那么 \(d(r, x) + d(x, y) + d(y, r) = 0, d(x, y) = -d(r, x) - d(y, r) = d(r, y) - d(r, x)\) 。

AC代码
// #define MULTIPLE_TASK
#include "hira/main.cpp"

#include "hira/ds/dsu.h"

void Initialize() {}

void SolveCase(int Case) {
  int n, m, q;
  std::cin >> n >> m >> q;

  ds::DSU d(n);
  std::vector<std::vector<std::pair<i64, int>>> g(n);
  for (int i = 0; i < m; ++i) {
    int a, b, c;
    std::cin >> a >> b >> c;
    --a, --b;

    d.merge(a, b);
    g[a].push_back({c, b});
    g[b].push_back({-c, a});
  }

  const i64 INF = INT64_C(0x3f3f3f3f3f3f3f3f);
  std::vector<i64> dist(n, -INF);
  std::vector<bool> has_positive_loop(n, false);
  for (int i = 0; i < n; ++i) {
    if (d.leader(i) != i)
      continue;

    std::queue<int> q;
    q.push(i);
    dist[i] = 0;
    while (!q.empty()) {
      int u = q.front();
      q.pop();

      for (auto [w, v] : g[u]) {
        if (dist[v] == -INF) {
          dist[v] = dist[u] + w;
          q.push(v);
        } else {
          if (dist[v] != dist[u] + w)
            has_positive_loop[i] = true;
        }
      }
    }
  }

  for (int i = 0; i < q; ++i) {
    int a, b;
    std::cin >> a >> b;
    --a, --b;

    if (!d.same(a, b)) {
      std::cout << "nan\n";
      continue;
    }

    if (has_positive_loop[d.leader(a)]) {
      std::cout << "inf\n";
      continue;
    }

    std::cout << -dist[a] + dist[b] << "\n";
  }
}

G - Do Use Hexagon Grid 2

在这种六角网格上,从 \((0, 0)\) 走到 \((x, y)\) 的距离为 \(\max(|x|, |y|, |x - y|)\)。

证明

感性的理解,六角网格是在四角网格的基础上,新增了右上和左下两个方向的移动。
对于右上方向和左下方向,横纵座标可以同时改变,其中一个到达目标值之后再仅改变另外一个。由此距离为 \(\max(|x|, |y|)\)。
对于左上和右下,只能先改一个座标,再改另一个座标,由此距离为 \(|x| + |y| = |x - y|\)。
综合一下就是距离为 \(\max(|x|, |y|, |x - y|)\)。

然后就可以把六角网格座标转换成三维座标,把距离看成三维座标系中的 Chebyshev 距离。

现在问题转换成有多少个点集满足点集中的点位于某一个 \(d \times d \times d\) 的正方体中。

为了防止重复计数,依次计算满足以下条件的点集 \(S\) 数量,然后再求和。(不断移动正方体,一旦移动一定会有某些点不再位于正方体中,从而达到去重的目的)

  • \(\min_{(x_i, y_i, z_i) \in S x_i} = x\)
  • \(\min_{(x_i, y_i, z_i) \in S y_i} = y\)
  • \(\min_{(x_i, y_i, z_i) \in S z_i} = z\)

将点集中的点 \((x_i, y_i, z_i)\) 分成 \(8\) 类:

  • \(x_i\) 是否为 \(x\)
  • \(y_i\) 是否为 \(y\)
  • \(z_i\) 是否为 \(z\)

假设集合名中出现 \(X\) 就表示满足 \(x_i = x\) 的点, \(Y\) 和 \(Z\) 同理。出现多个大写字母就是多个点集的交。三个座标都不满足的点集为 \(O\)。

再手动去重算点集数量。

  • 先将点集分成包含 \(XYZ\) 中点的和不包含的,包含了 \(XYZ\) 中点之后其他点都可以任意选,所以这一类数量为 \((2^{|XYZ|} - 1) 2^{|O| + |Z| + |Y| + |YZ| + |X| + |XZ| + |XY|}\)。
  • 此后都不能包含 \(XYZ\) 了,将点分为包含 \(XY\) 中点的和不包含的,,包含了 \(XY\) 中的还要再 \(Z \cup YZ \cup XZ\) 中至少选一个点,然后 \(O \cup Y \cup X\) 中的点可以任选。
  • 以此类推。
AC代码
// #define MULTIPLE_TASK
#include "hira/main.cpp"

#include "hira/math/modular/mod_int.h"
using mint = math::ModInt998;

#include "hira/std_extension/discretize.h"

void Initialize() {}

void SolveCase(int Case) {
  int n;
  i64 d;
  std::cin >> n >> d;

  std::vector<mint> p2(n + 1);
  p2[0] = 1;
  for (int i = 1; i <= n; ++i)
    p2[i] = p2[i - 1] * 2;

  std::vector<std::array<int, 3>> a(n);
  std::vector<int> xx(n), yy(n), zz(n);
  for (int i = 0; i < n; ++i) {
    int x, y, z;
    std::cin >> x >> y;
    z = x - y;

    a[i] = {x, y, z};
    xx[i] = x;
    yy[i] = y;
    zz[i] = z;
  }
  std::sort(
      a.begin(), a.end(),
      [](const std::array<int, 3>& lhs, const std::array<int, 3>& rhs) -> bool {
        return lhs[0] < rhs[0];
      });

  xx = stdext::discretize(xx);
  yy = stdext::discretize(yy);
  zz = stdext::discretize(zz);

  auto calc = [&](const std::array<int, 8>& c) {
    auto [none, z, y, yz, x, xz, xy, xyz] = c;

    mint ret(0);

    ret += (p2[xyz] - 1) * p2[none + z + y + yz + x + xz + xy];
    ret += (p2[xy] - 1) * (p2[z + yz + xz] - 1) * p2[y + x + none];
    ret += (p2[xz] - 1) * (p2[y + yz] - 1) * p2[z + x + none];
    ret += (p2[x] - 1) * (p2[yz] - 1) * p2[none + z + y];
    ret += (p2[x] - 1) * (p2[y] - 1) * (p2[z] - 1) * p2[none];

    return ret;
  };

  std::vector<std::array<int, 3>> p(n);
  auto solve = [&](int y, int z) {
    mint ret(0);

    int r = -1;
    std::array<int, 8> c = {0};

    int curr = 0;
    p.clear();

    for (int x : xx) {
      // previous points lies on left bound of x coordinate now invalid.
      // remove them.
      for (int t = 0; t < 8; ++t) {
        if (t & 0b100)
          c[t] = 0;
      }

      // new points fit in the range.
      while (r + 1 < n && a[r + 1][0] <= x + d) {
        ++r;
        if (a[r][1] < y || a[r][1] > y + d || a[r][2] < z || a[r][2] > z + d)
          continue;
        ++c[((a[r][1] == y) << 1) | (a[r][2] == z)];
        p.push_back(a[r]);
      }

      // update points lies on left bound of x coordinate.
      while (curr < p.size() && p[curr][0] == x) {
        --c[((p[curr][1] == y) << 1) | (p[curr][2] == z)];
        ++c[0b100 | ((p[curr][1] == y) << 1) | (p[curr][2] == z)];
        ++curr;
      }

      ret += calc(c);
    }

    return ret;
  };

  mint ans(0);
  for (int y : yy) {
    for (int z : zz) {
      ans += solve(y, z);
    }
  }

  std::cout << ans.value() << "\n";
}

Ex - Substring Sort

To be solved.

标签:std,AtCoder,hira,Beginner,int,p2,280,include,mint
From: https://www.cnblogs.com/zengzk/p/16950555.html

相关文章

  • AtCoder Beginner Contest 280
    D-FactorialandMultiple数论  首先上这道题需要的数论知识:n!的素因子分解中,n!=p1^a1*p2^a2*p3^a3*.....*pk^ak中对于素因数pi,其对于的ai=n/pi+n/p......
  • abc--280--F
    F-PayorReceive题目大意给你一个图,查询两个点的最长路边权是正着走是正数,反着走为负数无法到达为nan,无穷大为inf注意:会有重边和自环思路用并查集划分连通块,用df......
  • abc--280--E
    题目大意一个人有n条命,你有p%的概率一次打它两条命,有(100-p)%的概率一次打他一条命求你打死它需要的次数的期望值思路其实也就和走台阶的那个题目是一样的,用dp写就行了......
  • abc--280--D
    D-FactorialandMultiple题目大意找到一个最小的n,使得n的阶乘能整除k思路将它化为一堆的质数,然后满足这些质数至少需要多大的数最后这个找最大的数的时候,直接暴力......
  • AtCoder Beginner Contest 280 题解
    A-PawnonaGrid看样例猜题意(要求的是#的数量,直接判断。//If,oneday,Ifinallymanagetomakemydreamsareality...//Iwonder,willyoustillbethere......
  • AtCoder Beginner Contest 280 D-E
    D-FactorialandMultiple前置知识\(n!\)中包含素因子\(p\)的个数为\[cnt=\sum\limits_{k\geq1}^{p^k\leqn}\lfloor\frac{n}{p^k}\rfloor\]例如:\(n!\)......
  • ORA-28040: 没有匹配的验证协议
    问题:ORA-28040:没有匹配的验证协议原因:Oracle数据库安装的是12.2版本,OracleClient安装的版本是11(ODTwithODAC1120320_32bit)。解决:打开 sqlnet.ora 文件,增加以下两行......
  • mysql学习系列:总结数据库连接不上的数种情况,问题编号:ERROR 1045 (28000)
    (文章目录)场景今天重启CDH的时候,发现重启报错,查看日志才发现是mysql数据库连接不上。在尝试解决的过程中,踩到一些坑。所以总结一下,并分享给大家看看,减少大家伙继续踩坑的......
  • AtCoder Beginner Contest 247 题解
    AtCoderBeginnerContest247Solution目录AtCoderBeginnerContest247Solution更好的阅读体验戳此进入题面链接题面Luogu链接A-MoveRight题面SolutionCodeB-U......
  • 二维前缀和 P2280 激光炸弹
      #include<iostream>#include<algorithm>usingnamespacestd;ints[5005][5005],n,r;voidsov(){inti,j,ans=0;intx,y,z;cin>>n>>r;......