UVA 1649 Binomial coefficients

https://vjudge.net/problem/UVA-1649

题意:

输入m,求所有的C(n,k)=m

m<=1e15

如果枚举n,那么C(n,k)先递增后递减

如果枚举k,那么C(n,k)单调递增

所以可以枚举k,二分n,直至C(n,k)=m

k枚举到什么时候?

根据公式 C(n,k)=C(n,n-k)

所以只管那个小的k 

k<n-k 即 k<n/2,

也就是对于每个n,k只算到n/2

所以 当C(k*2,k)>m 时,停止枚举

然后对于这个k,二分n

边界:l=k*2,r=m

#include<queue>
#include<cstdio>
#include<iostream>
using namespace std;
#define pairr pair<long long,long long>
#define make(a,b) make_pair(a,b)
priority_queue<pairr,vector<pairr>,greater<pairr> >q;
long long n;
long long C(long long m,long long k)
{
    long long x=1;
    for(int i=1;i<=k;i++)
    {
        if(x/i>n/(m-i+1)) return n+1;
        x*=m-i+1;
        x/=i;
    }
    return x;
}
void solve()
{
    long long l,r,mid,tmp;
    for(int k=1;C(k<<1,k)<=n;k++)
    {
        l=k<<1;
        r=n;
        while(l<=r)
        {
            mid=l+r>>1;
            tmp=C(mid,k);
            if(tmp<n) l=mid+1;
            else if(tmp==n) 
            {
                q.push(make(mid,k));
                if(mid!=k<<1) q.push(make(mid,mid-k));
                break;
            }
            else r=mid-1;
        }
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    long long siz;
    while(T--)
    {
        scanf("%lld",&n);
        solve();
        siz=q.size();
        printf("%d
",siz);
        while(siz--)
        {
            printf("(%lld,%lld)",q.top().first,q.top().second);
            if(siz) printf(" ");
            else printf("
");
            q.pop(); 
        }
    }
}
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7424896.html