您的位置:首页 > 其它

[CP1804]组合数问题2

2018-04-02 20:34 162 查看

题目大意:
  给定两个数$n(n\le10^6)$和$k(k\le10^5)$,找到$k$个不同的满足$0\le b\le a\le n$的组合数$\binom a b$,求这$k$个组合数的最大值。

思路:
  显然对于同一个$a$,$b=\lfloor\frac a 2\rfloor$时组合数取到最大值,可以先对于所有的$0\le a\le n$求出$b=\lfloor\frac a 2\rfloor$时的组合数的值,用一个堆来维护。取走这个数同时把$a$相同的,仅次于它的组合数加入堆,比较时为避免精度问题用对数比较。时间复杂度$O(n\log n)$。

#include<queue>
#include<cmath>
#include<cstdio>
#include<cctype>
typedef long long int64;
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int N=1e6+1,mod=1e9+7;
int fact
,factinv
;
void exgcd(const int &a,const int &b,int &x,int &y) {
if(!b) {
x=1,y=0;
return;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
inline int inv(const int &x) {
int ret,tmp;
exgcd(x,mod,ret,tmp);
return (ret%mod+mod)%mod;
}
inline int calc(const int &a,const int &b) {
return (int64)fact[a]*factinv[b]%mod*factinv[a-b]%mod;
}
struct Node {
long double val;
int a,b,d;
bool operator < (const Node &another) const {
return val<another.val;
}
};
std::priority_queue<Node> q;
int main() {
const int n=getint(),k=getint();
for(register int i=fact[0]=1;i<=n;i++) {
fact[i]=(int64)fact[i-1]*i%mod;
}
factinv
=inv(fact
);
for(register int i=n;i;i--) {
factinv[i-1]=(int64)factinv[i]*i%mod;
}
for(register int a=0;a<=n;a++) {
if(a&1) {
q.push((Node){lgamma(a+1)-lgamma(a/2+1)-lgamma(a-a/2+1),a,a/2,-1});
q.push((Node){lgamma(a+1)-lgamma(a/2+2)-lgamma(a-a/2),a,a/2+1,1});
} else {
q.push((Node){lgamma(a+1)-lgamma(a/2+1)-lgamma(a-a/2+1),a,a/2,0});
}
}
int ans=0;
for(register int cnt=0;cnt<k;cnt++) {
int a=q.top().a,b=q.top().b,d=q.top().d;q.pop();
(ans+=calc(a,b))%=mod;
if(d!=1&&b!=1) q.push((Node){lgamma(a+1)-lgamma(b)-lgamma(a-b+2),a,b-1,-1});
if(d!=-1&&b!=a) q.push((Node){lgamma(a+1)-lgamma(b+2)-lgamma(a-b),a,b+1,1});
}
printf("%d\n",ans);
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: