Catalog
  1. 1. 1.stone
  2. 2. 2.memory
    1. 2.0.1. 60分做法
    2. 2.0.2. 100分做法
  • 3. 3.subset
  • 2019正睿Day2题解

    https://download.csdn.net/download/qq_45721135/11866498

    1.stone

    根据期望的线性性,答案 E(t) = P2 + P3 + · · · + Pn + 1,其中 Pi 是第 i 堆石子在第 1 堆之前被取走的概率。
    考虑第 i 堆,可以发现其他堆都不会影响这两堆,因此相当于只要考虑只有这两堆的情况,因此概率即为$\frac{ai}{a1 + ai}$。
    因此答案即为$\sum_{i=2}^{n}{\frac{ai}{a1 + ai}+1}$,直接计算即可。
    时间复杂度: Θ(n)。

    2.memory

    对于每个 x,考虑如果用它来压缩那么可以达到的最优解,设为 F(x)。
    假如给定一个 x,想要求 F(x),那么可以通过二分贪心在 Θ(n log2 n) 的时间内算出。
    直接对于所有 x 都暴力计算即可得到 Θ(nm log2 n) 的复杂度,可以通过子任务1, 2。
    如果我们以随机顺序遍历所有 x,则在期望情况下,新的 F(x) 比当前所有F 的值都要小的 x 个数的期望应该是 ∑ 1/i,这是调和级数,为 Θ(ln n)。
    于是我们只对于这些 x 二分即可:我们令答案为 ans − 1 并贪心,即可判断当前的 x 是否满足条件。
    时间复杂度: Θ(nm + n ln n log2 n)。

    使最大值最小,很显然这是一个二分。

    60分做法

    这个部分分还是非常好拿的,只需要枚举每一个x并二分求答案即可。

    时间复杂度:$O(nmlogn)$

    100分做法

    其实就是再60分做法的基础上做一个类似与搜索的最优化剪枝的优化。

    我们可以发现,当我们枚举到一个x的时候,当且仅当在$a[i]=(a[i]+x)%m$的基础上check(ans-1)成立(ans为区间[1,x-1]求得的最小值),这个x才有可能对答案产生贡献,所以我们在每次二分前根据check(ans-1)的情况去决定是否对x进行二分答案即可。

    注意,为了防止自己被卡,最好将x的枚举顺序打乱后再进行枚举。

    code:

    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
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<ctime>
    #include<algorithm>
    #define ll long long
    #define INF 0x7fffffff
    #define re register
    #define rep(i,a,b) for(int i = (a); i <= (b); i++)
    #define qwq printf("qwq\n");

    using namespace std;

    int read()
    {
    register int x = 0,f = 1;register char ch;
    ch = getchar();
    while(ch > '9' || ch < '0'){if(ch == '-') f = -f;ch = getchar();}
    while(ch <= '9' && ch >= '0'){x = x * 10 + ch - 48;ch = getchar();}
    return x * f;
    }

    int n,m,k,l,r,ti,mid,ans,sum,a[100005],b[100005],c[100005];

    bool check(int l)
    {
    int cnt = 1; sum = 0;
    for(int i = 1; i <= n; i++)
    {
    if(sum + b[i] > l) cnt++,sum = 0;
    sum += b[i];
    if(cnt > k) return false;
    }
    return true;
    }

    int cmp(int a,int b) {return rand() % 2;}

    int main()
    {
    n = read(); m = read(); k = read();
    srand(time(0));
    for(int i = 1; i < m; i++) c[i] = i;
    sort(c + 1, c + m,cmp);
    for(int i = 1; i <= n; i++) a[i] = read();
    ans = INF;
    for(int i = 1; i < m; i++)
    {
    int y = c[i];
    l = 0;
    for(int j = 1; j <= n; j++) b[j] = (a[j] + y) % m,sum += b[j],l = max(l,b[j]);
    r = min(ans,sum);
    while(l < r)
    {
    mid = (l + r) >> 1;
    if(check(mid)) r = mid,ans = min(ans,r);
    else l = mid + 1;
    }
    }
    printf("%d\n",ans);
    return 0;
    }

    3.subset

    显然我们只会选择 n 的约数,因为如果选了其他的那么最小公倍数一定不是 n。
    考虑对 n 进行分解,设 n = pα 1 1pα 2 2 · · · pα kk。那么我们要求选的数字满足:对于每个 i ∈ [1, k],均存在一个数在 pi 中是 0 次方,也存在一个数在 pi 中是 αi 次方。
    直接计算并不容易,考虑容斥原理:如果只有一个 pα,那么我们用所有情况去掉不存在 0 次方的情况,再去掉不存在 α 次方的情况,然后加上都不存在的情况即可。
    然后对于原问题,我们可以 Θ(4k) 枚举每个质因数是上面四种情况中的哪一种,然后计算出这种情况下的方案数即可。时间复杂度: Θ(4ω(n)ω(n)),可以通过子任务1, 2。
    考虑如何进行优化。注意到对于第一种情况,方案数为 (αi + 1),第二种和第三种情况都是 αi,而第四种是 (αi − 1)。因此,我们可以转而枚举方案数的可能性,这只有三种,因此枚举的复杂度从 Θ(4k) 降到了 Θ(3k)。
    值得一提的是,这里对 n 进行分解是本题的难点: Θ(√n) 的复杂度并不可以接受,但我们并不需要真的得到 p1, p2, · · · , pk,而是只要知道 α1, α2, · · · , αk 即可。
    我们考虑先分解出所有 pi ≤ √3 n 的 pα i i,那么剩余部分只有 p, p2, pq 三种,其中p, q 都是质数。
    那么我们先使用 Miller Rabin 算法判断 p 的情况,然后开根号后平方判断 p2 的情况,剩余的情况就是 pq 的情况了。
    时间复杂度: Θ(√3 n + 3ω(n)ω(n))。

    Author: wflight
    Link: http://yoursite.com/2019/10/19/2019正睿Day2题解/
    Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
    Donate
    • 微信
    • 支付寶

    Comment