poj-3252-数学

题意:

给你两个数x,y,让你求这两个数之间的循环数的数量。

循环数:把数转换为二进制,对于二进制,0比1多或者相等的数为循环数。

做法:

先分别求出0~x的循环数个数a,再求出0~y有的循环数个数b;结果为b-a;

求0~x的循环数个数:

假如x转化为2进制之后有5位;x=10100;

则先求出位数为1,2,3,4位的二进制数中有多少个循环数;

         求法:比如说位数为4位,则循环数个数为c(3,2)+c(3,3),因为4位第一位肯定为1,后面必须有2或者3个0;

然后再求出二进制为5位,且比10100小的循环数。

        求法:可以对10100从第二位到尾进行搜,如果这个位置为0,继续搜,如果为1,就假设此位为0,后面的数中补0或者1使得此二进制为循环数。

比如当第i位为3的时候,此时num[i]=1;若num[i]=0;.则存在c(2,0)+c(2,1)+c(2,2)个循环数。

最后如果y为循环数的话,总体结果加一。

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int csum(int x,int y)
{
    int sum=1,i;
    if(y==0||y==x)return 1;
    int chu=1;
    for(i=1;i<=y;i++)
    {
        chu*=i;
        sum*=(x-i+1);
        if(sum%chu==0)
        sum/=chu,chu=1;
    }

    return sum;
}
int chan(int len,int n0,int n1)
{
    if(len==0)return n0>=n1;
    int nlen=len;
    int i,need0=(nlen+n1-n0+1)/2;
    if(need0<0)need0=0;
    int sum=0;
    for(i=need0;i<=nlen;i++)
    {
        sum+=csum(nlen,i);
      //  printf("-------------csum(%d,%d)=%d\n",nlen,i,csum(nlen,i));
    }
    return sum;
}
int jisuan(long long num,int leap)
{
    long long sum;
    int sumber;
    sum=num;
    int lens,i;
    int n[100];
    lens=0;
    while(sum)
    {
        n[lens++]=sum%2;
        sum/=2;
    }
    sumber=0;
    for(i=1;i<lens;i++)
    {
        sumber+=chan(i-1,0,1);
      //  printf("first=chan(%d,%d,%d)=%d\n",i-1,0,1,chan(i-1,0,1));
    }
    if(lens>1)sumber++;
    int n1,n0;
    n1=1;
    n0=0;
  //  printf("sumber=%d\n",sumber);
    for(i=lens-2;i>=0;i--)
    {
        if(n[i]==0)n0++;
        if(n[i]==1)
        {
            n0++;
            sumber+=chan(i,n0,n1);
         //   printf("chan(%d,%d,%d)=%d\n",i,n0,n1,chan(i,n0,n1));
            n1++;n0--;
        }
    }
    if(lens==1)
    sumber++;
    if(leap==1&&n0>=n1)sumber++;
    return sumber;
}
int main()
{
    long long st,end;
    cin>>st;
    cin>>end;
    int x;
    int y;
    x=jisuan(st,0);
    y=0;
    y=jisuan(end,1);
    printf("%d\n",y-x);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值