P3048 [USACO12FEB]Cow IDs
思路:遞歸&組合數學。
顯然對於長度爲的串,包含個1且第一位爲的個數爲從中選出個1.
即:個。
所以我們每次可以求出第一個1在那個長度裏。然後先輸出距離上一輪的第一個1之間由多少個0,再輸出這輪的1,不斷遞歸,到最後,再輸出剩下0的個數。(因爲最後一個1後面再沒有1,全部是0,即輸出個0即可)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
int C(int n,int m){
int ans=1;
for(int i=n-m+1;i<=n;i++) ans*=i;
for(int i=1;i<=m;i++) ans/=i;
return ans;
}
int main(){
int n,k;
scanf("%d%d",&n,&k);
int pre=k-1,w;
for(;k;k--){ //遞歸每次的第一位的1.
w=k-1;
int x=C(w,k-1),sum=0;
while(sum+x<n){
sum+=x;
x=x*(++w)/(w-k+1); //不能寫 x*=(++w)/(w-k+1) 它會先算右式(++w)/(w-k+1)
}
for(int i=1;i<=pre-w-1;i++) printf("0"); //此時的(w+1)表示當求第一個1到最後一位的長度.
// 之前的剩下的長度爲pre,距離上一個第一位1的個數爲pre-(w+1),所以這之間的數要填0.
n-=sum,pre=w;//這裏pre=w,而不是=w+1,因爲每次要填一個1,所以剩下的數還要減去1.
printf("1");
}
for(int i=1;i<=w;i++) printf("0");
return 0;
}