第十四届浙江财经大学程序设计竞赛 I Interesting Set【组合数】

链接:https://www.nowcoder.com/acm/contest/89/I
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
Mr.Frog is researching integers.
He converts two integers X and Y into binary system without leading zeros, if they have the same quantity of 0 and the same quantity of 1 in the binary system, Mr.Frog will think these two integers are friendly.

For example, 5(10) = 101(2) and 6(10) = 110(2), both of them have two 1 and one 0 in the binary system, so Mr.Frog thinks 5 and 6 are friendly.

Now, Mr.frog gets an integer N and defines a sorted set S. The sorted set S consists of integers which are friendly with N and bigger than N. He wants to know what is the Kth integer in S.

Because Mr.Frog is on his way back from Hong Kong to Beijing, he wants to ask you for help.

输入描述:
The first line contains an integer T, where T is the number of test cases. T test cases follow.
For each test case, the only line contains two integers N and K.

• 1 ≤ T ≤ 200.
• 1 ≤ N ≤ 1018.
• 1 ≤ K ≤ 1018
输出描述:
For each test case, print one line containing “Case #x: y”, where x is the test case number (startingfrom 1) and y is the Kth integer in the sorted set S. If the integer he wants to know does not exist, y is“ IMPOSSIBLE”.

示例1
输入
2
9 2
7 4
输出
Case #1: 12
Case #2: IMPOSSIBLE
备注:
For the first case, the sorted set S is {10, 12}, so the 2nd integer is 12.
For the second case, the sorted set S is ∅, so the answer is “IMPOSSIBLE”.

好题!
题意:将一个数字转换为二进制,任何和它0,1个数相同的数字 都是友好的(不包括签前导0)。那么现在给你一个数x,求其之后的第y个友好的数是什么。

一开始做这个题的时候,听到了后面的队伍说到康托展开。可惜的是当时我并不知道康托展开也并不知道其实这个题根本用不到所谓的康托展开。我们倒是直接采用了暴力的方法,一发超时之后使用了二分进行了一些优化,到了比赛结束没交上去。虽然后来知道了即使交上去也还是TLE。

分析:0,1所构成的数字的方案数,可以用排列组合求得。我们所需要的所有Cnm实际上都可以从杨辉三角中找得,打个表就非常的方便。接下来需要完成的就是,已知数求是第几个和已知是第几个求数的问题。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#include<set>
#include<queue>
using namespace std;
#define ll long long int
const int maxn = 64;
ll c[maxn][maxn];
ll num[65];
int a, b;//sum=0,1
void init()
{
    c[0][0] = 1;
    for (int i = 1; i < maxn; i++) { c[i][0] = c[i][i] = 1; }
    for (int i = 2; i < maxn; i++) {
        for (int j = 1; j <= i - 1; j++)
            c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
    }
    //for (int i = 0; i < 20; i++) {
    //  for (int j = 0; j <= i; j++) {
    //      cout << c[i][j] << " ";
    //  }
    //  cout << endl;
    //}
}
void getnum(ll x) {
    while (x > 0) {
        if (x % 2) b++;
        else a++;
        x >>= 1;
        //cout << x << endl;
    }
}
ll cal(int a, int b, ll x) {
    int k = 0;
    //cout << k << endl;
    while (x) {
        num[++k] = x % 2;
        x >>= 1;
    }
    ll res = 1;
    for (int i = k; i > 0; i--) {
        if (num[i] == 1 && a > 0) res += c[a + b - 1][b];
        if (num[i] == 0) a--;
        else b--;
    }
    return res;
    //cout << res << endl;
}
ll solve(int a, int b, ll k) {
    int tmp = a + b;
    ll res = 0;
    for (int i = 0; i < tmp; i++) {
        if (k > c[a + b - 1][b]) {
            k = k - c[a + b - 1][b];
            b--;
            res = res * 2 + 1;
        }
        else {
            a--;
            res = res * 2;
        }
    }
    return res;
    //cout << res << endl;
}
int main()
{
    init();
    int T; int cs = 0;
    scanf("%d", &T);
    while (T--) {
        cs++;
        ll x, y; a = 0, b = 0;
        scanf("%lld%lld", &x, &y);
        getnum(x);
        y = y + cal(a, b, x);
        printf("Case #%d: ", cs);
        if (y > c[a + b][a]) printf("IMPOSSIBLE\n");
        else printf("%lld\n", solve(a, b, y));
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值