abc057d <贪心+组合计数>

D - Maximum Average Sets

// https://atcoder.jp/contests/abc057/tasks/abc057_d
// 贪心, 尽可能拿大的, 达到个数下限即可
// 注意, 不取模的组合数计算, 结果范围在1e18范围内, 如果直接计算阶乘也会溢出
// 1. 如下面的代码, 利用 C(n,m) = n!/m!/(n-m)!, 将三部分的质因数分解, 计算出幂次, 而后再相乘 
//   (此方法对于更大范围的不取模组合数计算,可将乘法换为高精度乘法)
// 2. 使用递推处理, C(n,m) = C(n-1,m) + C(n-1,m-1)
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
typedef long long LL;

// 注意: 直接这么计算会溢出 !!
// LL C(LL n, LL m)
// {
//     cout << "C " << n << ' ' << m << endl;
//     LL ans = 1;
//     LL t = 1;
//     for (int i = 1, j = n; i <= m; i++, j--)
//     {
//         ans *= j;
//         t *= i;
//     }
//     return ans / t;
// }

// 统计 n! 中质因子 p 的个数
LL get(LL n, LL p)
{
    LL res = 0;
    while (n)
    {
        res += n / p;
        n /= p;
    }
    return res;
}

LL qpow(LL a, LL k)
{
    LL res = 1;
    while (k)
    {
        if (k & 1) res *= a;
        k >>= 1;
        a *= a;
    }
    return res;
}

// 计算组合数
LL C(LL n, LL m)
{
    bool st[51] = {false};
    LL res = 1;
    for (int i = 2; i <= n; i ++)  // 遍历2~n内的质数
        if (!st[i])
        {
            for (int j = i + i; j <= n; j += i) st[j] = true;
            LL k = get(n, i) - get(m, i) - get(n-m, i);  // n! / m! / (n-m)! 中, 质因子 p 的幂次
            res *= qpow(i, k);
        }
    return res;
}

void solv()
{
    map<LL, LL> mp;
    LL n, a, b;
    cin >> n >> a >> b;
    for (int i = 0; i < n; i++)
    {
        LL t;
        cin >> t;
        mp[t]++;
    }
    double sum = 0;
    LL cnt = 0;
    for (auto i = mp.rbegin(); i != mp.rend(); i++)  // 注意这里map的逆向迭代的写法 (是i++)
    {
        if (cnt + i->second < a)  // 这里使用 ' -> '
        {
            cnt += i->second;
            sum += i->second * i->first;
        }
        else
        {
            if (i == mp.rbegin())
            {
                double ans1 = i->first;
                LL ans2 = 0;
                int lim = min(i->second, b);
                for (int j = a; j <= lim; j ++) ans2 += C(i->second, j);
                printf("%.6f\n%lld\n", ans1, ans2);
            }
            else
            {
                sum += double(a - cnt) * i->first;
                double ans1 = sum / a;
                LL ans2 = C(i->second, a - cnt);
                printf("%.6f\n%lld\n", ans1, ans2);
            }
            break;
        }
    }
    C(50, 5);
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T = 1;
    // cin >> T;
    while (T--)
    {
        solv();
    }
    return 0;
}
posted @   O2iginal  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示