Stringsobits
Kim Schrijvers

Consider an ordered set S of strings of N (1 <= N <= 31) bits. Bits, of course, are either 0 or 1.

This set of strings is interesting because it is ordered and contains all possible strings of length N that have L (1 <= L <= N) or fewer bits that are `1'.

Your task is to read a number I (1 <= I <= sizeof(S)) from the input and print the Ith element of the ordered set for N bits with no more than L bits that are `1'.

PROGRAM NAME: kimbits

INPUT FORMAT

A single line with three space separated integers: N, L, and I.

SAMPLE INPUT (file kimbits.in)

5 3 19

OUTPUT FORMAT

A single line containing the integer that represents the Ith element from the order set, as described.

SAMPLE OUTPUT (file kimbits.out)

10011
 
 
这是一道无耻的数学题......
是的,稍微观察一下,就可以发现这莫大的数据,不剪剪,过不了。
思路很清晰,就是往上一个一个找,找到地i个就好了,怎么缩小时间呢?
考虑一个1,把它放在一个位置j上,我们可以算出小于(1<<j)的数m有多少个。
j是一个二进制的数位,所以在其前面的位数有j个。
比如0001000,1前面就有三个零,而这个二进制的值=(1<<3)。
那么:m=C(j,0)+C(j,1)+......+C(j,min(j,m))。
这样,我们就可以估计第一个1的位置。
不过,这样还是要超时。
所以,同理,估计第二个1,第三个1......
你会发现,你找到了一个固定的数,它就是答案。
由于作者比较懒,没有写正解,当我发现,我确定了第一个1的位置,我TLE了,确定了第二个,还是TLE......
于是作者陷入了复制代码,加长代码的不归路(虽然最后还是AC,不过一点也不优美)
附上我的丑陋代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
long long k;
int dp[32][32];
int pos[32],t,pas,pass,passs;
int main()
{
    freopen("kimbits.in","r",stdin);
    freopen("kimbits.out","w",stdout);
    int i,j;
    scanf("%d%d%lld",&n,&m,&k);
    for(i=1;i<=31;++i)
    {
        dp[i][1]=i;
        dp[i][i]=1;
    }
    for(i=2;i<=31;++i)
        for(j=2;j<=i;++j)
            dp[i][j]=dp[i-1][j]+dp[i-1][j-1];
    long long num=1;
    for(i=1;i<=n;++i)
    {
        num=1;
        for(j=1;j<=min(i,m);++j)
            num+=dp[i][j];
        if(num==k)
        {
            for(j=1;j<=n-i;++j) printf("0");
            for(j=1;j<=min(i,m);++j) printf("1");
            for(j=1;j<=i-min(i,m);++j) printf("0");
            printf("\n");
            return 0;
        }
        if(num>k)
        {
            i--;
            num=1;
            for(j=1;j<=min(i,m);++j)
                num+=dp[i][j];
            k-=num;
            break;
        }
    }
    pas=i;
    for(i=1;i<=pas;++i)
    {
        num=1;
        for(j=1;j<=min(i,m-1);++j)
            num+=dp[i][j];
        if(num>=k)
        {
            i--;
            num=1;
            for(j=1;j<=min(i,m-1);++j)
                num+=dp[i][j];
            k-=num;
            break;
        }
    }
    pass=i;
    if(pass!=0&&n>=30)
    {
        for(i=1;i<=pass;++i)
        {
            num=1;
            for(j=1;j<=min(i,m-2);++j)
                num+=dp[i][j];
            if(num>=k)
            {
                i--;
                num=1;
                for(j=1;j<=min(i,m-2);++j)
                    num+=dp[i][j];
                k-=num;
                break;
            }
        }
        passs=i;
    }
    if(n>=30&&passs!=0)
    {
        for(i=1;i<=passs;++i)
        {
            num=1;
            for(j=1;j<=min(i,m-3);++j)
                num+=dp[i][j];
            if(num>=k)
            {
                i--;
                num=1;
                for(j=1;j<=min(i,m-3);++j)
                    num+=dp[i][j];
                k-=num;
                break;
            }
        }
    }
    if(n>=30)
    {
        if(i==0) i=(1<<pas)+(1<<pass)+(1<<passs)-1,k=1;
        else i=(1<<pas)+(1<<pass)+(1<<passs)+(1<<i)-1;
    }
    else
    {
        if(i==0) i=(1<<pas)-1,k=1;
        else i=(1<<pas)+(1<<i)-1;
    }
    //i=(1<<(i+1))-1;
    int p=0;
    while(p<k)
    {
        i++;
        j=i;
        t=0;
        while(j>0)
        {
            t++;
            pos[t]=j%2;
            j/=2;
        }
        int num=0;
        for(j=1;j<=t;++j) if(pos[j]==1) num++;
        if(num<=m&&t<=n) p++;
    }
    for(i=1;i<=n-t;++i) printf("0");
    for(i=t;i>=1;--i) printf("%d",pos[i]);
    printf("\n");
    return 0;
}
my Code

还有buffms大神的优美代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
long long q[40][40];
int time1[40];
void add(int s){
    int t=2;
    while(s!=1){
        if(s%t==0){
            time1[t]++;
            s/=t;
        }else t++;
    }
    return;
}
void shan(int s){
    int t=2;
    while(s!=1){
        if(s%t==0){
            time1[t]--;
            s/=t;
        }else t++;
    }
    return;
}
long long c(int p,int q){
    if(p<q)return 0;
    long long ans=1;
    memset(time1,0,sizeof(time1));
    for(int i=1;i<=p;i++)add(i);
    for(int i=1;i<=q;i++)shan(i);
    for(int i=1;i<=(p-q);i++)shan(i);
    for(int i=1;i<=p;i++){
        for(int j=1;j<=time1[i];j++){
            ans*=i;
        }
    }
    return ans;
}
long long get(int pos,int len){
    long long ans=0;
    for(int i=1;i<=len;i++){
        ans+=q[pos-1][i];
    }
    return ans+1;
}
void wait(){
    for(int i=1;i<=32;i++){
        for(int j=i;j>=0;j--){
            q[i][j]=c(i,j);
        }
    }
}
int dp[1000];
int main(){
    freopen("kimbits.in","r",stdin);
    freopen("kimbits.out","w",stdout);
    int n,l;
    long long k;
    wait();
    scanf("%d%d",&n,&l);
    cin>>k;
    int last=l;
    while(k!=0){
        for(int i=1;i<=n+1;i++){
            long long getans=get(i,last)+1;
            if(k<getans){
                dp[i-1]=1;
                k-=get(i-1,last);
                last--;
                break;
            }else if(k==getans){
                dp[i]=1;
                k-=getans;
                break;
            }
        }
    }
    for(int i=n;i>=1;i--)
        printf("%d",dp[i]);
    printf("\n");
}

全是0.000s哦!!!!!

此题还是一道很不错的题目,推荐自己好好想一下。