[CP1804]组合数问题2
题目大意:
给定两个数$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)$。
1 #include<queue> 2 #include<cmath> 3 #include<cstdio> 4 #include<cctype> 5 typedef long long int64; 6 inline int getint() { 7 register char ch; 8 while(!isdigit(ch=getchar())); 9 register int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 const int N=1e6+1,mod=1e9+7; 14 int fact[N],factinv[N]; 15 void exgcd(const int &a,const int &b,int &x,int &y) { 16 if(!b) { 17 x=1,y=0; 18 return; 19 } 20 exgcd(b,a%b,y,x); 21 y-=a/b*x; 22 } 23 inline int inv(const int &x) { 24 int ret,tmp; 25 exgcd(x,mod,ret,tmp); 26 return (ret%mod+mod)%mod; 27 } 28 inline int calc(const int &a,const int &b) { 29 return (int64)fact[a]*factinv[b]%mod*factinv[a-b]%mod; 30 } 31 struct Node { 32 long double val; 33 int a,b,d; 34 bool operator < (const Node &another) const { 35 return val<another.val; 36 } 37 }; 38 std::priority_queue<Node> q; 39 int main() { 40 const int n=getint(),k=getint(); 41 for(register int i=fact[0]=1;i<=n;i++) { 42 fact[i]=(int64)fact[i-1]*i%mod; 43 } 44 factinv[n]=inv(fact[n]); 45 for(register int i=n;i;i--) { 46 factinv[i-1]=(int64)factinv[i]*i%mod; 47 } 48 for(register int a=0;a<=n;a++) { 49 if(a&1) { 50 q.push((Node){lgamma(a+1)-lgamma(a/2+1)-lgamma(a-a/2+1),a,a/2,-1}); 51 q.push((Node){lgamma(a+1)-lgamma(a/2+2)-lgamma(a-a/2),a,a/2+1,1}); 52 } else { 53 q.push((Node){lgamma(a+1)-lgamma(a/2+1)-lgamma(a-a/2+1),a,a/2,0}); 54 } 55 } 56 int ans=0; 57 for(register int cnt=0;cnt<k;cnt++) { 58 int a=q.top().a,b=q.top().b,d=q.top().d;q.pop(); 59 (ans+=calc(a,b))%=mod; 60 if(d!=1&&b!=1) q.push((Node){lgamma(a+1)-lgamma(b)-lgamma(a-b+2),a,b-1,-1}); 61 if(d!=-1&&b!=a) q.push((Node){lgamma(a+1)-lgamma(b+2)-lgamma(a-b),a,b+1,1}); 62 } 63 printf("%d\n",ans); 64 return 0; 65 }