2 条题解

  • 0
    @ 2025-6-4 16:11:20

    我们设 wchi,jwch_{i,j} 表示如果有 ii 位二进制数,如果第 jj 位放 11 那么至少是多少名

    然后我们用组合数处理就好,最后注意全为 00 也是一种方案数

    #include<iostream>
    #include<cstdio>
    #define N 2005
    #define int long long
    using namespace std;
    bool Test_MLE_start;
    int T=1,n,m,k,now=0;
    int ans[N],wch[N][N],C[N][N];
    inline int reads(){
    	char c=getchar();
    	int sum=0,f=1;
    	while(!isdigit(c)){
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(isdigit(c)){
    		sum=(sum<<3)+(sum<<1)+(c^'0');
    		c=getchar();
    	}
    	return sum*f;
    }
    inline void files(){
    	freopen("std.in","r",stdin);
    	freopen("std.out","w",stdout);
    }
    inline void clr(){
    //	Don't forget!
    
    }
    int finds(int L,int R,int x,int cnt){
    	while(L<R){
    		int mid=(L+R+1)>>1;
    		if(wch[mid][cnt]<=x) L=mid;
    		else R=mid-1;
    	}
    	return L;
    }
    bool Test_MLE_end;
    signed main(){
    //	printf("%lf Mb\n",(&Test_MLE_end-&Test_MLE_start-1)/1024.0/1024.0);
    //	files();
    //	T=reads();
    	while(T--){
    		clr();
    		for(int i=0;i<=N-5;i++){
    			C[i][0]=1;
    			for(int j=1;j<=i;j++){
    				C[i][j]=C[i-1][j]+C[i-1][j-1];
    			}
    		}
    		n=reads(),m=reads(),k=reads();
    		for(int i=0;i<=n;i++){
    			for(int j=0;j<=m;j++){
    				wch[i][j]=1;
    				for(int p=0;p<=j;p++){
    					wch[i][j]+=C[i-1][p];
    				}
    			}
    		}
    //		for(int i=0;i<=n;i++){
    //			for(int j=0;j<=m;j++){
    //				cout<<wch[i][j]<<" ";
    //			}
    //			puts("");
    //		}
    		while(k>1&&m){
    			int nxt=finds(1,n,k,m);
    //			cout<<nxt<<" "<<m<<" "<<wch[nxt][m]<<":"<<k<<"->";
    			k-=wch[nxt][m],m--;
    			k++;
    //			cout<<k<<"\n";
    			ans[nxt]=1;
    		}
    		for(int i=n;i>=1;i--) printf("%d",ans[i]);
    	}
    	return 0;
    }
    /*
    000111010110111100110101100011
    000111010110111100110101100011
    */
    
    • 0
      @ 2025-6-3 16:03:28

      从高到低依次确定每一位,假设现在是从右往左的第 ii 位,后边还要放 jj 个零,那么剩下的 ii 位就还有 C(i,j)C(i,j) 种放法,但题目说是至多 jj 个,所以把组合数累加就可以了。

      假设现在他的排名为 kk,后面如果放0,有s种放法。那么如果k>s,这一位就应该是1,要k-=s。

      #include<bits/stdc++.h>
      #define int long long
      
      using namespace std;
      int n,m,k;
      int C[50][50],s[50][50];
      int ans[50];
      signed main(){
      	std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
      	cin>>n>>m>>k;
      	C[1][0]=C[1][1]=1;
      	for(int i=2;i<=n;++i){
      		C[i][0]=1;
      		for(int j=1;j<=i;++j){
      			C[i][j]=C[i-1][j]+C[i-1][j-1];
      		}
      	}
      	s[0][0]=1;
      	for(int j=1;j<=n;++j){
      		s[0][j]=1;
      	}
      	for(int i=1;i<=n;++i){
      		s[i][0]=C[i][0];
      		for(int j=1;j<=n;++j){
      			s[i][j]=s[i][j-1]+C[i][j];
      		}
      	}
      	for(int i=n,cnt=0;i>=1;--i){
      		if(m>cnt&&k>s[i-1][m-cnt]){
      			k-=s[i-1][m-cnt];
      			++cnt;
      			ans[i]=1;
      		}
      	}
      	for(int i=n;i>=1;--i){
      		cout<<ans[i];
      	}
      	return 0;
      }
      

      注意求前缀和的时候j=0的也要算,否则最后一位会出错

      • 1

      信息

      ID
      244
      时间
      1000ms
      内存
      256MiB
      难度
      5
      标签
      (无)
      递交数
      36
      已通过
      15
      上传者