P3048 [USACO12FEB]Cow IDs

P3048 [USACO12FEB]Cow IDs

传送门

思路:递归&组合数学。

显然对于长度为lenlen0101串,包含kk个1且第一位为11的个数为从len1len-1中选出k1k-1个1.

即:C(n1,k1)C(n-1,k-1)个。

所以我们每次可以求出第一个1在那个长度里。然后先输出距离上一轮的第一个1之间由多少个0,再输出这轮的1,不断递归,到最后k=0k=0,再输出剩下0的个数。(因为最后一个1后面再没有1,全部是0,即输出ww个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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章