poj3252组合数学

来源:互联网 发布:db2数据库创建用户 编辑:程序博客网 时间:2024/05/01 06:01

题意:一个数转换成二进制数,零的个数大于等于一的个数的数称为圆数,例如9转换成1001,0的个数为2,1的个数为2,所以9为圆数;输入两个数start和end,问start到end有多少个圆数。
思路:start到end中有多少个圆数,我们只需要求出num[0,start]和num[0,end),num[0,start]-num[0,end)即为所求;
以二进制数10011000为例,位数为8,那么位数小于8的圆数有多少个?
以位数为7的情况来解释,首先保证没有前导0,这样只需要考虑剩下的6位,然后要保证零的个数大于等于一的个数,即从6个位置里面挑出大于等于一半的位置为0,组合问题不用多说了吧。枚举位数小于8的情况,再枚举为圆数的情况,求和即可;
当位数等于8时,首先我们既要保证前导零,又要保证所枚举的数不能大于本身,那么我们从第二位开始枚举每一位,记下零的个数,当枚到1时,情况就于位数小于的情况一样。一样的处理方式。详情看代码吧。

#include<iostream>#include<algorithm>#include<string>#include<cstring>#include<map>#include<queue>#include<cmath>#include<stack>#include<vector>#include<cstdio>#define MAXN 33000#define INF 0x3f3f3f3f#define lmid l,m,rt<<1#define rmid m+1,r,rt<<1|1#define ls rt<<1#define rs rt<<1|1#define Mod 1000000007#define i64 __int64#define LIMIT_ULL 100000000000000000#define Max(a,b) (a>b)?a:b#define lowbit(x) x&(-x)using namespace std;typedef long long ll;int c[33][33]={0};//c[i][j]表示从i个物品中挑j个的情况数int bin[35];void deal()//组合数打表{     for(int i=0;i<=32;i++)          for(int j=0;j<=i;j++)     {          if(!j||i==j)               c[i][j]=1;          else               c[i][j]=c[i-1][j-1]+c[i-1][j];     }}void dealbin(int n)//转换成二进制{     bin[0] = 0;     while(n)     {          bin[++bin[0]]=n%2;          n/=2;     }}int solve(int n){     int sum=0;     dealbin(n);     for(int i=1;i<bin[0]-1;i++)//位数小于的情况,且保证没有前导0,实际位数为i+1          for(int j=i/2+1;j<=i;j++)//挑出j个位置为0          sum+=c[i][j];     int zero=0;     //从高位向低位搜索过程中出现0的位的个数     for (int i=bin[0]-1;i>=1;i--)     {          if (bin[i])          {               for (int j=(bin[0]+1)/2-(zero+1);j<=i-1;j++)               {                    sum+=c[i - 1][j];               }          }          else zero++;     }     return sum;}int main(){     deal();     int a,b;     while(scanf("%d%d",&a,&b)==2)     cout<<solve(b+1)-solve(a)<<endl;//solve(b)并没有判断b为不为圆数,所以为solve(b+1)-solve(a)     return 0;}
原创粉丝点击