1 条题解
-
3wdvxdr LV 8 MOD @ 2017-11-08 17:53:17
友情提示:公式小看不清的话,可以将网页放大!
比较简单的组合数问题,不会组合数取余的可以看一下这篇文章:
http://www.cnblogs.com/linyujun/p/5194189.html我们可以先将序列进行排序,那么对于第\(i\)个数,他被做为最小数的方案有\(\binom{n-i}{k-1}\)
即从剩下的比它的数选\(k-1\)个数的方案数。需要用到的公式\(\binom{n}{m}=\frac{n!}{m!(n-m)!}\)
我们可以先预处理出阶乘,以及其逆元,然后再套用上面公式。
怎样求逆元呢?
我们可以先用费马小定理求\(n!\)的逆元。
然后就可以得到
\(inv[i-1] = inv[i] \times i\)其中\(inv[i]\)代表 \(i !\) 的逆元。为什么?
结合逆元的定义就可以知道是这样子的了
具体实现参照下面代码
#include<bits/stdc++.h> using namespace std; const int maxn = 200000+10,p=1e9+7; int n,k,inv[maxn],fac[maxn],c[maxn]; long long ksm(int a,int b) { long long ret = 1; while(b) { if(b&1) ret = 1ll*ret*a%p; a = 1ll*a*a%p; b >>= 1; } return ret; } void init() { fac[0]=1; for(int i=1;i<=n;i++)//预处理阶乘 fac[i] = 1ll*fac[i-1]*i%p; inv[n] = ksm(fac[n],p-2);//费马小定理求逆元 for(int i=n-1;i>=0;i--)//预处理阶乘的逆元 inv[i] = 1ll*inv[i+1]*(i+1)%p; } inline long long comb(int a,int b) { if(b>a) return 0; return 1ll*fac[a]*inv[b]%p*inv[a-b]%p;//用组合数的公式 } int main() { long long ans = 0; scanf("%d%d",&n,&k); init(); for(int i=1;i<=n;i++) scanf("%d",&c[i]); sort(c+1,c+n+1); for(int i=1;i<=n-k+1;i++) { ans = (ans + 1ll * c[i] * comb(n-i,k-1)%p)%p; } cout << ans << endl; return 0; }
- 1
信息
- 难度
- 8
- 分类
- (无)
- 标签
- (无)
- 递交数
- 30
- 已通过
- 5
- 通过率
- 17%
- 上传者