1777:寻找整数

1777:寻找整数

时间限制: 1000 ms         内存限制: 262144 KB
【题目描述】

给定整数m,k,求出正整数n使得n+1,n+2,…,2n 中恰好有m个数在二进制下恰好有k个1。有多组数据。
【输入】

第一行一个整数 t表示数据组数。接下来 t 行每行两个整数m,k。
【输出】

每组数据输出一行两个整数,第一个数表示264-1范围内任意一个满足条件的 n,第二个数表示满足条件的 n 的个数(无穷多用-1表示)。保证1018以内存在满足条件的 n。

如果每组数据第一个数全部正确,得4分。

如果每组数据第二个数全部正确,得6分。

【输入样例】

1
1 2

【输出样例】

2 1

【提示】

【数据规模】

对于10%的数据,k=2。

对于20%的数据,k≤3。

对于另外50%的数据,保证满足条件的 n均在1018以内。

对于100%的数据,t≤2000,0≤m≤1018,1≤k≤64。

【题解】

发现题目所求等于1有k的个数的数随着n增加单调递增,所以答案一定在一个区间内。

我们就可以二分出区间的上下界,现在问题就是如何求出区间内1等于k的数的个数。

按照常规差分成1-n-1,1-2n。

对于一个x,强制其每一位为1的位为0,前头为1的位都为1,后头有好多种方法,用组合数求解。

代码如下:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf=2e18+5;
int t,m,k,f[75][75],C[74][75];
inline int solve(int x)
{
    int i,j=0,daan=0;
    x++;
    for(int i=62;i>=0;i--)
    {
        if(x&(1ll<<i))
        {
            if(k>=j) daan+=C[i][k-j];
            j++;
        }
    }
    return daan;
}
inline int check(int x)
{
    return solve(2ll*x)-solve(x);
}
inline int find()
{
    int l=1,r=inf,daan;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(check(mid)<m) l=mid+1;
        else r=mid-1,daan=mid;
    }
    return daan;
}
signed main()
{
    cin>>t;
    for(int i=0;i<=70;i++) C[i][0]=1;
    for(int i=1;i<=70;i++) for(int j=1;j<=i;j++) C[i][j]=C[i-1][j-1]+C[i-1][j];
    while(t--)
    {
        cin>>m>>k;
        if(m==0)
        {
            cout<<"1 "<<(1ll<<k-1)-1<<"
";
            continue;
        }
        if(k==1&&m==1)
        {
            cout<<"1 -1
";
            continue; 
        }
        int hu1=find();
        m++;
        int hu2=find();
        cout<<hu1<<" "<<hu2-hu1<<"
";
    }
}
View Code
原文地址:https://www.cnblogs.com/betablewaloot/p/12247293.html