题解 P4370 【[Code+#4]组合数问题2】
[Code+#4]组合数问题2
求
容易发现
于是一开始可以将所有的
然而并没有A掉这道题(不然也太水了)。
发现是组合数太大,导致优先队列无法比较。
于是可以考虑对组合数取对数,然后比较,就可以了。
注意
做一个
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
const int N=1e6+50;
const int mod=1e9+7;
typedef long long LL;
typedef double D;
typedef pair<int,int> pr;
typedef pair<D,pr> prr;
int n,k;
LL jc[N],ny[N],ans;
D lg[N];
priority_queue <prr>pg;
LL ksm(LL u,LL v){
LL ret=1;
for(;v;u=u*u%mod,v>>=1)
if(v&1)ret=ret*u%mod;
return ret;
}
void pre(int ha){
jc[0]=ny[0]=1;
for(int i=1;i<=ha;i++)jc[i]=jc[i-1]*i%mod;
ny[ha]=ksm(jc[ha],mod-2);
for(int i=ha;i>=2;i--)
ny[i-1]=ny[i]*i%mod;
for(int i=1;i<=ha;i++)
lg[i]=lg[i-1]+log(i);
//预处理阶乘、逆元、对数
}
int main(){
pre(N-50);
scanf("%d%d",&n,&k);
for(int i=0;i<=n;i++)pg.push(prr(lg[n]-lg[n-i]-lg[i],pr(n,i)));
//初始将C(n,i)丢进去
for(int i=1;i<=k;i++){
int x=pg.top().second.first;
int y=pg.top().second.second;
pg.pop();
ans=(ans+jc[x]*ny[y]%mod*ny[x-y]%mod)%mod;
x--;
pg.push(prr(lg[x]-lg[x-y]-lg[y],pr(x,y)));
//每次取出最大的,丢进去新的
}
printf("%lld\n",ans);
}