zoukankan      html  css  js  c++  java
  • 最大数的和

    题意:有N个数,每次从中任意选取K个数,取其中的最大值,求所有组合能取得的最大值的和.N100,000,K50,输出结果对1000000007取模的结果.0≤每个数10^9​​

    样例输入1

    5 2
    1 2 3 4 5

    样例输出1

    40

    样例输入2

    5 3
    1 2 3 4 5

    样例输出2

    45

    分析:很显然,这是一道组合数学的题目。其实我们只需要求出每个数作为最大值出现的次数就能够得到答案.如果一个数能够作为最大值出现,那么这个数肯定大于等于第k大的数,先排序.

           我们要找到当前数作为最大数的次数,这由比他小的数来决定.对于样例2,我们考虑3这个数,将3固定在最高位,那么我们还需要确定k-1个数,这k-1个数可以取任意的比3小的数,例如1,2或2,1两个组合,也就是说如果我们当前考虑的数是第i大的数,那么只需要计算出c[i-1][k-1](i-1个数中选k-1个数的方案个数)再乘以这个数即可.

           然而,本题要求取模,不能直接计算组合数,可以使用逆元来计算,但是这样有点复杂,如果我们直接递推则可以直接取模(不涉及到除法),这样有一个问题:内存占用太大,这道题用long long,开数组内存花费太大了,怎么办呢?可以发现递推组合数的时候状态i的结果只与状态i-1的结果有关,所以可以使用滚动数组!代码如下:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    
    #define maxn 100010
    
    using namespace std;
    
    const int MOD = 1e9 + 7;
    
    long long p[maxn];
    
    long long f[2][maxn];
    
    long long ans;
    int k, n;
    void work() { f[0][0] = 1; int i, j; bool flag = 1; for (i = 1;i <= n - 1;i++) { int m = min(i,k-1); for (j = 0;j <= m;j++) { if (j == 0 || j == i) f[flag][j] = 1; else f[flag][j] = (f[!flag][j - 1] + f[!flag][j]) % MOD; } if (k - 1 <= i) ans += p[i + 1] * f[flag][k - 1] % MOD; ans %= MOD; flag = !flag; } } int main() { scanf("%d%d", &n, &k); for (int i = 1;i <= n;i++) scanf("%d", &p[i]); sort(p + 1, p + 1 + n); work(); printf("%lld", ans); return 0; }

              

  • 相关阅读:
    javascript中的对象创建与继承
    Requirejs快速使用
    HTML5服务器推送事件
    使用html+css实现三角标示符号
    thinkphp结合bootstrap打造个性化分页
    angularjs学习笔记3-directive中scope的绑定修饰符
    angularjs学习笔记2—运行phonecat项目
    grunt-contrib-qunit安装过程中phantomjs安装报错问题解决
    angularjs学习笔记1-angular总体简介及其特点
    Mybatis详细配置过程
  • 原文地址:https://www.cnblogs.com/zbtrs/p/6817462.html
Copyright © 2011-2022 走看看