您的位置:首页 > 其它

数位DP(组合数打表)—— Round Numbers ( POJ 3252 )

2016-07-20 20:15 417 查看
题目链接:

http://poj.org/problem?id=3252

分析:

求出S~F中转换成二进制数后0的个数≥1的个数的数字的个数。0的个数大于1的个数的数可以用组合数来做。

题解:

算出1~F+1和1~S的满足条件的个数相减即可。

先一个数转换乘二进制形式存入数组中:

void change(int n)
{
number[0]=0; //nubmer[0]用来存储二进制数总长度
while(n)
{
number[++number[0]]=n%2;//逆序存储二进制数
n/=2;
}
return;
}


然后先将长度小于number[0]的所有满足条件的数算出,这个非常简单,就是满足C(≥(len/2), len)(从len个数中挑≥(len/2)个)的所有数就是题意。

再将number[0]长度下满足条件的数计算出来,从最高位往下搜索即可:

int round(int n)
{
int i,j;
int sum=0;  //比十进制数n小的所有RN数
change(n);
//cout << number[0] << endl;
/*计算长度小于number[0]的所有二进制数中RN的个数*/

for(i=1;i<number[0]-1;i++)
for(j=i/2+1;j<=i;j++)
sum += dp[i][j];

/*计算长度等于number[0]的所有二进制数中RN的个数*/
int zero=0;  //从高位向低位搜索过程中出现0的位的个数
for(i=number[0]-1;i>=1;i--)
if(number[i])   //当前位为1
for(j=(number[0]+1)/2-(zero+1);j<=i-1;j++)//前面已经出现zero个0了,所以需要减去它
sum+=dp[i-1][j];
else
zero++;

return sum;
}


AC代码:

#include<iostream>
using namespace std;

int dp[33][33]={0};
int f[33][33];
int number[35];

void init()
{
for(int i=0;i<=32;i++)
for(int j=0;j<=i;j++)
{
if(!j || i==j)
dp[i][j] = 1;
else
dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
//cout << i << "  " << j << ":  " << dp[i][j] << endl;

}
return;
}

/*十进制n转换二进制,逆序存放到number[]*/

void change(int n)
{
number[0]=0;
while(n)
{
number[++number[0]]=n%2;
n/=2;
}
return;
}

/*计算比十进制数n小的所有RN数*/

int round(int n)
{
int i,j;
int sum=0;  //比十进制数n小的所有RN数
change(n);
//cout << number[0] << endl;
/*计算长度小于number[0]的所有二进制数中RN的个数*/

for(i=1;i<number[0]-1;i++)
for(j=i/2+1;j<=i;j++)
sum += dp[i][j];

/*计算长度等于number[0]的所有二进制数中RN的个数*/
int zero=0;  //从高位向低位搜索过程中出现0的位的个数
for(i=number[0]-1;i>=1;i--)
if(number[i])   //当前位为1
for(j=(number[0]+1)/2-(zero+1);j<=i-1;j++)
sum+=dp[i-1][j];
else
zero++;

return sum;
}

int main()
{
init();
int a,b;
cin>>a>>b;
cout<<round(b+1)-round(a)<<endl;

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息