P5815 CQOI2010 扑克牌

P5815 CQOI2010 扑克牌 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

首先 \(J\) 是个障眼法,稍微思考可知它和数字牌无区别。直接把 \(J\) 当作 \(0\) 号牌即可。也就是 \(n + 1\) 张牌中一次拿 \(n\) 张不同的牌。

容易想到这种拿法相当于,给某种牌添一张,然后在 \(n+1\) 种牌中每种牌都取一张。

又可发现答案具有单调性,二分答案,转化为判定性问题:是否可以拿 \(x\) 次?

\(x\) 次可以分解为:先考虑添 \(x\) 次牌,然后取 \(x\) 次牌。显然等价于添 \(x\) 次牌使得每种牌的数量不少于 \(x\)

计算一下把每种牌补到 \(x\) 张需要补的牌数是否超过 \(x\) 即可。

算一下二分右边界。答案最大显然应该是 \(n = 2\)\(m = c_1 =c_2 = 5 \times 10^8\) 的情况,算一下是 \(7.5 \times 10^8\)。这就是右边界了。

时间复杂度 \(\mathcal{O}(n\log c)\)

\(n\) 的数据范围有点诈骗……

/*
 * @Author: crab-in-the-northeast 
 * @Date: 2022-10-21 10:53:06 
 * @Last Modified by: crab-in-the-northeast
 * @Last Modified time: 2022-10-21 10:59:48
 */
#include <bits/stdc++.h>
inline int read() {
    int x = 0;
    bool flag = true;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-')
            flag = false;
        ch = getchar();
    }
    while (isdigit(ch)) {
        x = (x << 1) + (x << 3) + ch - '0';
        ch = getchar();
    }
    if(flag)
        return x;
    return ~(x - 1);
}

const int maxn = 55;
int a[maxn];
int n;

inline bool check(int x) {
    long long t = 0;
    for (int i = 0; i <= n; ++i)
        if (x > a[i])
            t += x - a[i];
    
    return t <= x;
}

int main() {
    n = read();
    for (int i = 0; i <= n; ++i)
        a[i] = read();
    
    int ans = 0;
    
    for (int i = (1 << 30); i; i >>= 1)
        if (check(ans + i))
            ans += i;
    
    printf("%d\n", ans);
    return 0;
}
posted @ 2022-10-21 11:02  dbxxx  阅读(42)  评论(0编辑  收藏  举报