AtCoder Regular Contest 118 解题报告

本文同步发表在 YangTY’s Blog

ARC118A - Tax Included Price

打表可做。

ARC118B - Village of M People

Description

给定 K K K N N N M M M 以及 K K K A i A_i Ai,构造 B i B_i Bi,使得 ∑ B i = M \sum B_i = M Bi=M
max ⁡ i ∣ B i M − A i N ∣ \max_i\left|\frac{B_i}{M} - \frac{A_i}{N}\right| imaxMBiNAi
最小。

Solution

“最大的最小”,二分答案即可。

要让 max ⁡ i ∣ B i M − A i N ∣ \max_i\left|\frac{B_i}{M} - \frac{A_i}{N}\right| maxiMBiNAi 最小,即为让 max ⁡ i ∣ B i N − A i M ∣ \max_i|B_iN - A_iM| maxiBiNAiM 最小,设为 x x x 即可。

然后我们可以得到 ∀ i , ⌈ M A i − x N ⌉ ≤ B i ≤ ⌊ M A i + x N ⌋ \forall i, \left\lceil \frac{MA_i-x}{N}\right\rceil\leq B_i\leq \left\lfloor\frac{MA_i+x}{N}\right\rfloor i,NMAixBiNMAi+x。这样子 B i B_i Bi 的上界和下界就出来了,设为 L i L_i Li R i R_i Ri

然后,如果 ∑ L i ≤ M ≤ ∑ R i \sum L_i\le M\le \sum R_i LiMRi,则答案一定是可以被构造出来的。这样子我们就可以完成对于一个 x x x 的 check。

如何构造这个答案呢?把所有的 B i B_i Bi 设为 L i L_i Li,然后依次上调来补齐余量 M − ∑ L i M - \sum L_i MLi

这题就做完了。

#include 
#include 
#include 
#define FOR(i, a, b) for (int i = a; i <= b; ++i)
#define DEC(i, a, b) for (int i = a; i >= b; --i)
#define int long long

const int maxn = 1e5 + 5;

int read()
{
    int s = 0, x = 0;
    char c = getchar();
    while (!isdigit(c))
        x |= (c == '-'), c = getchar();
    while (isdigit(c))
        s = s * 10 + c - '0', c = getchar();
    return x ? -s : s;
}

int k, a[maxn], n, m;
int L[maxn], R[maxn], suml, sumr;

inline int max(int a, int b) {return a > b ? a : b;}
inline int min(int a, int b) {return a < b ? a : b;}

bool check(int x)
{
    memset(L, 0, sizeof L), memset(R, 0, sizeof R);
    suml = sumr = 0;
    FOR(i, 1, k)
    {
        L[i] = max(0, (m * a[i] - x + n - 1) / n);
        R[i] = (m * a[i] + x) / n;
        suml += L[i], sumr += R[i];
    }
    return suml <= m && m <= sumr;
}

signed main()
{
    k = read(), n = read(), m = read();
    FOR(i, 1, k) a[i] = read();
    int l = 0, r = n * m, x;
    while (l <= r)
    {
        int mid = (l + r) >> 1;
        if (check(mid)) x = mid, r = mid - 1;
        else l = mid + 1;
    }
    check(x);
    int sumb = suml;
    FOR(i, 1, k)
    {
        int x = min(R[i] - L[i], m - sumb);
        sumb += x;
        printf("%d ", x + L[i]);
    }
    return 0;
}

ARC118C - Coprime Set

Description

给定 N N N 3 ≤ N ≤ 2500 3\le N\le 2500 3N2500),构造 N N N 个正整数 A i A_i Ai 使得:

  • A i A_i Ai 互不相同且 A i ∈ [ 1 , 10000 ] A_i\in[1, 10000] Ai[1,10000]
  • ∀ i ≠ j , gcd ⁡ ( A i , A j ) > 1 \forall i \not= j, \gcd(A_i, A_j) > 1 i=j,gcd(Ai,Aj)>1
  • gcd ⁡ i { A i } = 1 \gcd_i\{A_i\} = 1 gcdi{Ai}=1

Solution

这个题需要一个引理:对于一系列已经满足条件的 A i A_i Ai,将任意 A i A_i Ai 的倍数加进去,新得到的集合也是满足条件的。

正确性比较显然,不证。所以从 { 6 , 10 , 15 } \{6, 10, 15\} {6,10,15} 出发,就可以构造出所有的合法答案。

#include 

int vis[10005];

int main()
{
    int n = 0;
    scanf("%d", &n);
    for (int i = 1; i * 6 <= 10000; ++i) vis[i * 6] = 1;
    for (int i = 1; i * 10 <= 10000; ++i) vis[i * 10] = 1;
    for (int i = 1; i * 15 <= 10000; ++i) vis[i * 15] = 1;
    int cnt = 4;
    printf("%d %d %d\n", 6, 10, 15), vis[6] = vis[10] = vis[15] = 0;
    for (int i = 6; i <= 10000 && cnt <= n; ++i) if (vis[i]) printf("%d ", i), ++cnt;
    return 0;
}

你可能感兴趣的:(题解)