【组合】奶牛编号

题目描述

作为一个神秘的电脑高手,Farmer John 用二进制数字标识他的奶牛。

然而,他有点迷信,标识奶牛用的二进制数字,必须只含有K位“1” (1 <= K <= 10)。 当然,每个标识数字的首位必须为“1”。

FJ按递增的顺序,安排标识数字,开始是最小可行的标识数字(由“1”组成的一个K位数)。

不幸的是,他没有记录下标识数字。请帮他计算,第N个标识数字 (1 <= N <= 10^7)。

输入

第1行:空格隔开的两个整数,N和K。

输出

如题,第N个标识数字

输入样例

7 3

输出样例

10110


组合,暴力,推演?
不停寻找个lln,使 lln位填k位的方案数 < n <= lln+1位填k位的方案数(就是说第n大的数在lln位数中最大的数和lln+1位数中最大的数中间),然后在lln+1位填上1,用n减去lln作新的n,然后寻求的k减去1.


Code

#include
#define LLL long long
LLL n,k;
LLL Ans[10000001];
LLL C(LLL nn, LLL mm){   //组合:n里取m个的方案数
 LLL lll = 1;
 for(LLL i = nn-mm+1; i <= nn; ++i) lll = lll * i;
 for(LLL i = 2; i <= mm; ++i) lll = lll/i;
 return lll;
}
LLL cl(LLL ln, LLL kk){  //求第ln个数,kk=剩余几个1没填
 if(ln == 0 || kk == 0) return 0;
 LLL ans = 0,lln = kk;
 while(ans<n){
  ans = C(lln,kk);  //lln位填满所能得到的方案数
  if(ans >= ln){  //如果这么填超过了要求的(其实就是找到了要填1的地方
   Ans[lln] = 1;  //填上个1
   if(lln>kk) ans=cl(ln-C(lln-1,kk),kk-1); //下一位之后,填kk-1个1
   break;
  }
  ++lln; //少于,加多一位试试
 }
 return lln;
}
int main(){
 scanf("%lld%lld",&n,&k);
 for(LLL i = cl(n,k); i; --i)  
   putchar(48+Ans[i]); //快输
}

你可能感兴趣的:(暴力/模拟,数论)