标签:clu sed 递增 进制 ++ long int ace onclick
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<<"\n"; continue; } if(k==1&&m==1) { cout<<"1 -1\n"; continue; } int hu1=find(); m++; int hu2=find(); cout<<hu1<<" "<<hu2-hu1<<"\n"; } }
标签:clu sed 递增 进制 ++ long int ace onclick
原文地址:https://www.cnblogs.com/betablewaloot/p/12247293.html