334

B-Christmas Trees

Description

有一条向东西两侧无限延伸的道路,从这条道路上的某一参考点向东 x 米处的点的坐标定义为 x。其中,从参考点向西 x 米处的一点的坐标为 x

斯努克将从坐标为 A 的点开始,以 M 米的间隔在路上的各点摆放圣诞树。换句话说,他将在每一个可以用某个整数 k 表示为 A+kM 的点上摆放一棵圣诞树。

高桥和青木分别站在坐标为 LR 的点上。(LR)。求在高桥和青木之间(包括他们所站的点)将会有多少棵圣诞树。

Constraints

Input

AMLR

Output

打印将在高桥和青木之间设置的圣诞树数量(包括他们所站的位置)。

Sample Input

5 3 -1 6

Sample Output

3

Solution

首先,让我们通过从 LR 中减去 A 来简化问题,这样圣诞树就站在坐标的倍数上。

k 为站在坐标 kM 处的树的索引。设 l 为站在严格小于 L 的坐标处的最东边的树的索引,

r 则是站在坐标小于或等于 R 的最东边的树的索引。那么答案就是 rl

现在剩下的是找到站在小于或等于 x 的坐标处的最东边的树的索引,对于某个 x;这简单地表示为 xM。请注意,当 x 为负数时,根据编程语言的不同,找到 xM 的方法也有所不同。(例如,在 C++中,你不能简单地写 x/M。)此外,通过对浮点数进行求值以获得实数然后进行取下限可能会因为精度误差而导致错误的值,所以请小心。

Code

ans=(R - A - ((R - A) % M + M) % M) / M - (L - 1 - A - ((L - 1 - A) % M + M) % M) / M
官方题解是

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
ll floor(ll x, ll m) {
    ll r = (x % m + m) % m;
    return (x - r) / m;
}
int main() {
    ll a, m, l, r;
    cin >> a >> m >> l >> r;
    l -= a, r -= a;
    cout << floor(r, m) - floor(l - 1, m) << endl;
}

C-Socks 2

问题陈述

高桥有 N 双袜子,其中 i 双由两只颜色为 i 的袜子组成。一天,高桥在整理抽屉时发现自己丢失了 A1,A2,,AK 种颜色的袜子各一只,于是他决定用剩下的 2NK 只袜子做 2NK2 双新袜子,每双由两只袜子组成。一双颜色为 i 的袜子和一双颜色为 j 的袜子的怪异度定义为 |ij|,高桥希望将总怪异度最小化。

求用剩下的袜子做成 2NK2 对时,总奇异度的最小值。请注意,如果 2NK 是奇数,那么将有一只袜子不包含在任何一对袜子中。

Constraints

Input

N      KA1    A2AK

Output

将最小总怪异度打印为整数。

Sample Input

4 2
1 3

Sample Output

2

Notes

下面,让 (i,j) 表示一对颜色为 i 的袜子和一对颜色为 j 的袜子。
颜色为 1,2,3,4 的袜子分别有 1,2,1,2 只。创建 (1,2),(2,3),(4,4) 这对袜子后,总奇异度为 |12|+|23|+|44|=2,即最小奇异度。

Solution

首先,最优的方案是匹配他没有丢失的袜子。

因此,这个问题可以被看作是一个问题,要求从颜色 A1,A2,,AK 中的每一个颜色中挑选一只袜子,制造 K2 对袜子。

如果 K 是偶数,最优的配对方式似乎是配对 (A1,A2),(A3,A4),,(AK1,AK),这是确实的情况。

K 是奇数时,问题就出现了。在这种情况下,我们可以在剩下的袜子中暴力解决唯一没有配对的颜色的问题,最优的方法可以像我们处理偶数 K 一样找到。当剩下的袜子配对时,最小的总奇异度可以在 O(N) 的时间内找到,但这导致了 O(N2) 的复杂度。而实际上,我们可以预先计算当前几只袜子配对时的总的奇异度,例如 presum[2]=(A2A1),presum[4]=(A4A3)+(A2A1),presum[6]=(A6A5)+(A4A3)+(A2A1),,以类似前缀和的方式。同样,可以找到“后缀和”。因此,通过这种方法,问题可以在总共 O(N) 的时间内解决。

额外信息:当 K 是奇数时,相比于对每只未配对的袜子暴力尝试,我们可以只尝试 A1,A3,A5,,AK(证明省略)。在下面的示例代码中,我们采用了这种方法来简化实现。

Code

需要计算前缀(pre)和后缀(suf)

#include<bits/stdc++.h>
using namespace std;
int main() {
    int n, k;
    cin >> n >> k;
    vector<int> a(k);
    for (int &i: a) cin >> i;
    vector<int> pre(k + 1), suf(k + 1);
    for (int i = 1; i <= k; i++) {
        pre[i] = pre[i - 1];
        if (i % 2 == 0) pre[i] += a[i - 1] - a[i - 2];
    }
    for (int i = k - 1; i >= 0; i--) {
        suf[i] = suf[i + 1];
        if ((k - i) % 2 == 0) suf[i] += a[i + 1] - a[i];
    }
    int ans = 1e9;
    for (int i = 0; i <= k; i += 2) {
        ans = min(ans, pre[i] + suf[i]);
    }
    cout << ans << endl;
}