您的位置:首页 > 其它

SOJ Binary Numbers dp + 逼近思想

2012-11-26 19:03 411 查看
题意:给定k(k<=10000000)和n(n<=10),问在由n个1组成的二进制数中第k大的数的二进制是什么。

题解:看到题就想到是构造,由于问的是第k大,那么逐步逼近。

预处理出dp[ i ][ j ][ 0 ]表示末 i 位中有 j 个1且当前位为0的方法数,dp[ i ][ j ][ 1 ]表示末 i 位中有 j 个1且当前位为1的方法数,

然后从高位到低位扫一遍即可。但是由于n = 1的时候可以直接得到答案,所以n = 2为极限情况,所以预处理到4500即可。

Sure原创,转载请注明出处

#include <cstdio>
#include <string>
#include <algorithm>
#include <iostream>
#include <memory.h>
#define MIN(a , b) ((a) < (b) ? (a) : (b))
using namespace std;
const int maxn = 4500;
int dp[maxn][12][2],ans[maxn];
int n,m;

void init()
{
memset(dp,0,sizeof(dp));
dp[1][1][1] = dp[1][0][0] = 1;
for(int i=2;i<maxn;i++)
{
int oo = MIN(10 , i);
for(int j=0;j<=oo;j++)
{
int a,b;
if(j)
{
a = dp[i-1][j-1][0],b = dp[i-1][j-1][1];
if(a != -1 && b != -1 && a + b <= 10000000) dp[i][j][1] = a + b;
else dp[i][j][1] = -1;
}
a = dp[i-1][j][0];
b = dp[i-1][j][1];
if(a != -1 && b != -1 && a + b <= 10000000) dp[i][j][0] = a + b;
else dp[i][j][0] = -1;
}
}
return;
}

void solve()
{
scanf("%d %d",&m,&n);
if(n == 1)
{
printf("1");
for(int i=0;i<m-1;i++) printf("0");
puts("");
return;
}
if(m == 1)
{
for(int i=0;i<n;i++)
{
printf("1");
}
puts("");
return;
}
memset(ans,0,sizeof(ans));
for(int i=maxn-1;i>=1 && n;i--)
{
if((dp[i]
[0] != -1 && dp[i]
[0] < m) || i == n)
{
ans[maxn-i] = 1;
m -= dp[i]
[0];
n--;
}
else ans[maxn-i] = 0;
}
int i=1;
for(;i<maxn && ans[i] == 0;i++);
for(;i<maxn;i++)
{
printf("%d",ans[i]);
}
puts("");
return;
}

int main()
{
init();
int cas;
scanf("%d",&cas);
while(cas--)
{
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: