习题10-21 二项式系数 UVa1649

来源:互联网 发布:7月中国进出口数据 编辑:程序博客网 时间:2024/06/04 18:06

1.题目描述:点击打开链接

2.解题思路:本题利用枚举+二分解决。问题的关键是选对枚举对象,因为要找C(n,k)=m,如果枚举n的话,一旦m非常大,枚举n就会十分困难。因此枚举对象应为k。根据组合数的性质易知,C(n,n/2)时是最大值,C(n,1)是最小值。由于固定的是k,因此n=2*k时是最小的范围,n=m是最大的范围,这样,即可通过二分法来寻找n。

本题有一个技巧,即在计算组合数时候,不必完整的计算完毕,只要发现中间已经超过了m,说明这个n肯定不是解,返回m+1即表示无解。

3.代码:

#define _CRT_SECURE_NO_WARNINGS #include<iostream>#include<algorithm>#include<string>#include<sstream>#include<set>#include<vector>#include<stack>#include<map>#include<queue>#include<deque>#include<cstdlib>#include<cstdio>#include<cstring>#include<cmath>#include<ctime>#include<functional>using namespace std;#define pll pair<long long,long long>#define M(a,b) make_pair(a,b)using namespace std;priority_queue<pll, vector<pll >, greater<pll > >q;long long m;long long c(int k, long long n){int i;long long f = 1;for (i = 1; i <= k; i++){if ((f / i)>(m / (n - i + 1)))//如果发现算到第i步时结果已经超过m了,说明n肯定不是解,返回一个m+1return m + 1;f *= (n - i + 1);f /= i;}return f;}void chk(){long long l, r, mid, t;int k;for (k = 1; c(k, 2 * k) <= m; k++)//最小的范围是C(k,2*k){l = k * 2;r = m;while (l <= r){mid = (l + r) >> 1;t = c(k, mid);if (t == m){q.push(M(mid, k));if (mid == k * 2) break;q.push(M(mid, mid - k));break;}else if (t<m)l = mid + 1;elser = mid - 1;}}}int main(){//freopen("t.txt", "r", stdin);int n, i;scanf("%d", &n);for (i = 1; i <= n; i++){cin >> m;chk();if (q.size()){printf("%d\n", q.size());int len = q.size();for (int i = 0; i < len; i++){printf("(%lld,%lld)%c", q.top().first, q.top().second, i == len - 1 ? '\n' : ' ');q.pop();}}elseputs("0\n");}return 0;}


0 0
原创粉丝点击