Featured image of post 1400

1400

No Prime Differences

出处:CF1838C

题目大意:给定 $n \times m$ 的矩阵,要求在其中填入 $1 \sim n \cdot m$ 的整数,使得网格中任意相邻单元格的绝对差不是质数。

数据范围: $4 \leq n,m \leq 1000, 1 \leq sum(n \cdot m) \leq 10^6$

思路:首先考虑 $n$ 和 $m$ 中有一个是合数的情况,显然按顺序填就可以。

然后,若它们都是质数,那么只需考虑每一行跳的是 $2 \cdot m$ 即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
bool check(int x) {
    if (x == 1) return false;
    for (int i = 2; i * i <= x; i++) {
        if (x % i == 0) return false;
    }
    return true;
}
void solve() {
    int n, m;
    cin >> n >> m;
    vvi a(n, vi(m));
    if (!check(m)) {
        rep(i, 0, n - 1) { rep(j, 0, m - 1) a[i][j] = i * m + j + 1; }
    } else if (!check(n)) {
        rep(j, 0, m - 1) { rep(i, 0, n - 1) a[i][j] = j * n + i + 1; }
    } else {
        rep(i, 0, n / 2) { rep(j, 0, m - 1) a[i][j] = 2 * m * i + j + 1; }
        rep(i, n / 2 + 1, n - 1) { rep(j, 0, m - 1) a[i][j] = m + 2 * m * (i - n / 2 - 1) + j + 1; }
    }
    rep(i, 0, n - 1) {
        rep(j, 0, m - 1) cout << a[i][j] << ' ';
        cout << endl;
    }
    return;
}

Vlad and a Pair of Numbers

出处:CF1790E

题目大意:给定 $x=a \bigoplus b,$ 问是否存在 $a,b$ ,使得 $\frac{a+b}{2}=x$ ,此处除法为实数除法,若存在则输出任意解,若不存在则输出-1.

数据范围: $1 \leq x \leq 2^{29}$ 。

思路:考虑异或性质,发现异或为1的位贡献是确定的,0的贡献是不确定的,于是判断对于 $x$ 的每个为1的位,后面都需要跟着至少一个0,答案为 $\frac{3x}{2}$ 和 $\frac{x}{2}$ 。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void solve() {
    ll x;
    cin >> x;
    vi tem2;
    int te = bit_width((unsigned)x) - 1;
    ll tem = 0;
    frep(i, te, 0) {
        if ((x >> i) & 1) {
            if (i == 0 || ((x >> (i - 1)) & 1)) {
                cout << -1 << endl;
                return;
            }
        }
    }
    int a = 0, b = 0;
    frep(i, te, 0) {
        if ((x >> i) & 1)
            a += (1 << i);
        else {
            if (i != te && ((x >> (i + 1)) & 1)) {
                a += (1 << i);
                b += (1 << i);
            }
        }
    }
    cout << a << ' ' << b << endl;
    return;
}

Array and GCD

出处:CF2104D

题目大意:给定一个大小为 $n$ 的数组 $a$ ,每次需要执行一次以下操作:

  • 支付一枚硬币,并将数组中的任意一个元素增加1,但是不能贷款。
  • 获得一枚硬币,并将数组中的任意一个元素减少1。

现在定义这样的一个数组是好的:

  • 每个元素至少为2。
  • 对于任意两个元素,它们都互质,如果元素数量少于2,那么自动满足这个条件。

现在要让这个数组变好,最少需要删除多少个数字?

数据范围: $1 \leq n \leq 4 \cdot 10^5, 2 \leq a_i \leq 10^9$

思路:看到最少其实很容易想到二分,不过这里其实不二分直接O(N)也可以,做麻烦了。

随后观察到对于某个取出的数组进行操作,则元素和应当小于等于原来的元素和。

考虑最少的条件,一个很直觉的东西就是,所有元素是按顺序排下来的最小 $k$ 个质数,然后就等价于原来的元素和大于等于这些质数的和,而根据贪心原来的元素和又可以取到原本数组中最大的 $k$ 个元素,于是做一下前缀和即可。

这里需要用到一些素数的筛法,我这边用了欧拉筛,它是一种 $O(n)$ 的筛法,基于每个合数只被它的最小素因子筛出的原理来做的,因此可以求出最小素因子,不过这里用埃氏筛也可以。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
constexpr int MX = 6e6 + 1;
bool pd[MX];
vi primes;
auto init = [] {
    rep(i, 2, MX - 1) {
        if (!pd[i]) primes.push_back(i);
        for (int& p : primes) {
            if (1LL * p * i >= MX) break;
            pd[i * p] = true;
            if (i % p == 0) break;
        }
    }
    return 0;
}();
void solve() {
    int n;
    cin >> n;
    vi a(n);
    rep(i, 0, n - 1) cin >> a[i];
    sort(all2(a));
    vl pre(n);
    pre[0] = a[0];
    rep(i, 1, n - 1) pre[i] = pre[i - 1] + 1LL * a[i];
    vl pre2(n);
    pre2[0] = primes[0];
    rep(i, 1, n - 1) pre2[i] = pre2[i - 1] + 1LL * primes[i];
    int l = 1, r = n, mid, ans = 1;
    auto check = [&](int mid) -> bool {
        if (mid == 1) return true;
        return pre[mid - 1] >= pre2[mid - 1];
    };
    while (l <= r) {
        mid = (l + r) / 2;
        if (check(mid)) {
            ans = mid;
            l = mid + 1;
        } else
            r = mid - 1;
    }
    cout << n - ans << endl;
    return;
}
本博客已稳定运行
发表了54篇文章 · 总计349.50k字
使用 Hugo 构建
主题 StackJimmy 设计