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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章