CCPC Harbin

GYM 104813 B

题目描述

给定一个数列 \(A\),你要对每个 \(\sum \limits_{j=1}^i 2^{j-i}\cdot A_j\) 判断其正负性。

思路

首先我们可以让其变为 \(\sum \limits_{j=1}^i 2^{j-1}\cdot A_j\),这里介绍一种叫做平衡三进制的做法。

平衡三进制类似于二进制,不同的是,其中一位上可以是 \(-1\)。平衡三进制的优点是可以不用处理退位的问题,只需进位。我们用 set 记录哪些位上不为 \(0\) 和其值。判断正负性只需看最高位即可。

空间复杂度 \(O(N)\),时间复杂度 \(O(N\log N\log A_i)\)

思路

#include<bits/stdc++.h>
using namespace std;
using pii = pair<int, int>;

const int MAXN = 100001;

int n;
set<pii> s;

void add(int p, int x) {
  auto it = s.lower_bound({p, -1});
  if(it != s.end() && it->first == p) {
    int v = it->second + x;
    s.erase(it);
    if(v == 2) {
      add(p + 1, 1);
    }else if(v == -2) {
      add(p + 1, -1);
    }
  }else {
    s.insert({p, x});
  }
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n;
  for(int i = 1, x; i <= n; ++i) {
    cin >> x;
    for(int j = 0; j <= 30; ++j) {
      if((abs(x) >> j) & 1) {
        add(j + i - 1, max(-1, min(1, x)));
      }
    }
    if(s.empty()) {
      cout << 0;
    }else {
      int x = prev(s.end())->second;
      cout << (x > 0 ? '+' : '-');
    }
  }
  return 0;
}

GYM 104813 D

题目描述

我们定义正整数 \(x\) 的质因子数量为 \(\omega (x)\)。我们把正整数看做结点,那么结点 \(x,y\) 之间有一条边权为 \(\omega(\operatorname{lcm}(x,y))\) 的边。求仅包含结点 \(l,l+1,\dots,r\) 的子图的最小生成树。

思路

首先 \(\omega(\operatorname{lcm}(x,y))=\omega(x)+\omega(y)-\omega(\gcd(x,y))\)。所以我们可以枚举 \(\gcd=x\)。接着我们枚举 \(x\) 的倍数 \(y\),找到 \(\omega(y)\) 最小的那个,那么其他 \(x\) 的倍数一定都会向 \(y\) 连边。我们对每种边权记录边并 kruskal 即可。

空间复杂度 \(O(r)\),时间复杂度 \(O(r\log r)\)

代码

#include<bits/stdc++.h>
using namespace std;
using pii = pair<int, int>;

const int MAXN = 1000001;

int t, l, r, w[MAXN], ans, f[MAXN], sz[MAXN];
vector<pii> g[13];

int getfa(int u) {
  return (f[u] == u ? u : f[u] = getfa(f[u]));
}

void Merge(int u, int v) {
  u = getfa(u), v = getfa(v);
  if(u != v) {
    if(sz[u] > sz[v]) {
      swap(u, v);
    }
    f[u] = v, sz[v] += sz[u];
  }
}

void Solve() {
  cin >> l >> r;
  for(int i = 0; i <= 12; ++i) {
    g[i].clear();
  }
  for(int i = 1; i <= r; ++i) {
    int pos = 0;
    for(int j = i; j <= r; j += i) {
      if(j >= l && (!pos || w[pos] > w[j])) {
        pos = j;
      }
    }
    for(int j = i; j <= r; j += i) {
      if(j >= l) {
        g[w[pos] + w[j] - w[i]].emplace_back(pos, j);
      }
    }
  }
  iota(f + l, f + r + 1, l);
  fill(sz + l, sz + r + 1, 1);
  ans = 0;
  for(int w = 0; w <= 12; ++w) {
    for(auto [u, v] : g[w]) {
      u = getfa(u), v = getfa(v);
      if(u != v) {
        Merge(u, v);
        ans += w;
      }
    }
  }
  cout << ans << "\n";
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  for(int i = 2; i < MAXN; ++i) {
    if(!w[i]) {
      for(int j = i; j < MAXN; j += i) {
        w[j]++;
      }
    }
  }
  for(cin >> t; t--; Solve()) {
  }
  return 0;
}
posted @ 2024-09-30 21:06  Yaosicheng124  阅读(5)  评论(0编辑  收藏  举报