usaco 3.2 Stringsobits 数位dp

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

 求二进制长度为N(可包括前导0)的1的个数不超过L的第I个数。

反着想,设第I个数为m,数位dp可以很轻松地求出[0,m]的符合条件(二进制长度为N(可包括前导0)的1的个数)的数的个数k,显然m是第k个数。

因此直接二分判断就可以了。

/*
ID: xidian5601
PROG: kimbits
LANG: C++
*/
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

ll N,L,I;
ll f[40][40];
int num[40],len;

ll dfs(int i,int cnt,int e)
{
    if(i==-1) return cnt<=L;
    if(!e&&~f[i][cnt]) return f[i][cnt];
    ll res=0;
    int u=e?num[i]:1;
    REP(d,0,u){
        if(cnt+d<=L) res+=dfs(i-1,cnt+d,e&&d==u);
    }
    return e?res:f[i][cnt]=res;
}

ll F(ll n)
{
    len=0;
    while(n){
        num[len++]=n%2;
        n/=2;
    }
    return dfs(len-1,0,1);
}

int cnt(ll n)
{
    int res=0;
    while(n){
        res+=n%2;
        n/=2;
    }
    return res;
}

ll bin(ll l,ll r,ll kth)
{
    while(l<=r){
        ll m=(l+r)>>1;
        ll t=F(m),c=cnt(m);
        if(c<=L&&t==kth) return m;
        if(t==kth&&c>L) r=m-1;
        else if(t>kth) r=m-1;
        else l=m+1;
    }
}

void Print(ll n)
{
    len=0;
    while(n){
        num[++len]=n%2;
        n/=2;
    }
    REP(i,len+1,N) printf("0");
    for(int i=len;i>=1;i--) printf("%d",num[i]);puts("");
}

int main()
{
    //freopen("in.txt","r",stdin);
    freopen("kimbits.in","r",stdin);
    freopen("kimbits.out","w",stdout);
    while(cin>>N>>L>>I){
        memset(f,-1,sizeof(f));
        Print(bin(0,(1LL<<N)-1,I));
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/--560/p/5186835.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值