1. 程式人生 > >CodeForces-431D Random Task(二分答案+數位)

CodeForces-431D Random Task(二分答案+數位)

題意

給定 mmkk ,求一個 nn 使得 [n+1,2n][n+1,2n] 範圍內的數中二進位制恰好有 kk11 的數,恰有 mm 個。 0m10180 \leq m \leq 10^{18} 1k641 \leq k \leq 64

思路

有一個“顯然”的單調性,nn 越大,[n+1,2n][n+1,2n] 中的數含有 kk11 的數單調不減,無論 kk 的取值。 其實也不難證,當 n1n-1 變為 nn 時,區間從 [n,2n2][n,2n-2] 挪到 [n+1,2n

][n+1,2n] 時,我們失去了 nn,獲得了 2n1,2n2n-1,2n ,而 2n2nnn 的二進位制含有的 11 數相同,而多的那個 2n12n-1 又不會讓含有 kk11 的數變少,由此得出單調性。 那就直接二分 nn,用數位dp\text{dp}驗證答案即可。

程式碼

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include
<algorithm>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=(y);++i) #define DOR(i,x,y) for(int i=(x),i##END=(y);i>=(y);--i) typedef long long LL; using namespace std; LL dp[70][70],m; int num[70],K; LL dfs(int k,int status,bool ismax) { if(k==0)return status==K; if(~dp[k][status]&&
!ismax)return dp[k][status]; int maxer=ismax?num[k]:1;LL res=0; FOR(i,0,maxer)res+=dfs(k-1,status+i,ismax&&i==maxer); if(!ismax)dp[k][status]=res; return res; } LL solve(LL k) { int n=0; while(k) { num[++n]=k%2; k>>=1; } return dfs(n,0,1); } int main() { scanf("%lld%d",&m,&K); memset(dp,-1,sizeof(dp)); LL L=1,R=1e18; while(L<R) { LL mid=L+R>>1; if(solve(mid*2)-solve(mid)>=m) { R=mid; } else L=mid+1; } printf("%lld\n",L); return 0; }