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(); } } }