今天上通选课笑尿了,外教让分组不能说话用纸搭塔。。
题意
定义:一个数字x为 round number 当且仅当 x的二进制形式中0的数量大于等于1的数量。
给两个数字start, finish,问两个数字之间(inclusive)有多少个round number。
输入输出
Input
Line 1: Two space-separated integers, respectively Start and Finish.
Output
Line 1: A single integer that is the count of round numbers in the inclusive range Start..Finish
分析
拖了好久 没做的题,今天想了想就想出来啦。
首先很正常的思路,找start 和finish之间的round number数量就等于找小于finish的rn减去小于start的rn。
对于一个数字x的二进制形式,有如下递推:
- 开头第一位,必定为1,所有比x二进制位数小的rn都可,递归找(1<<(len-1))-1的rn。
- 非第一位,为0,在更高位没有减小的情况下(更高位减小的情况涉及的情况在下一种情况),无法减小此位以减小整个数字,直接循环下一位。
- 非第一位,为1,将此位减小为0,此位之后的数字需满足0的数量要求,用组合数求此位之后的数字满足要求的数量。之前所说更高位减小的情况即此。之后循环下一位。
代码实现有点挫,debug了一会。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define mxn 33
int start,finish;
long long c[mxn][mxn];
long long s[mxn][mxn];
void set_c(){
for(int i=1;i<mxn;++i){
c[i][0]=1;
c[i][1]=i;
}
for(int i=2;i<mxn;++i)
for(int j=1;j<=i;++j)
c[i][j]=c[i-1][j]+c[i-1][j-1];
memset(s,0,sizeof(s));
for(int i=1;i<mxn;++i)
for(int j=0;j<mxn;++j)
for(int k=j;k<=i;++k)
s[i][j]+=c[i][k];
s[0][0]=1;
}
long long help(int len,int zero){
if(zero<0) zero=0;
return s[len][zero];
}
long long calc(int tem){
if(tem==0||tem==1) return 1;
long long ret=0;
int num[40];
int len=0;
int zero=0;
int haha=tem;
while(tem){
num[len++]=tem%2;
if(tem%2==0) ++zero;
tem/=2;
}
if(zero>=len/2+len%2){
++ret;
//cout<<"0: "<<ret<<" "<<haha<<endl;
}
for(int i=0;i<len/2;++i){
num[i]=num[i]+num[len-1-i];
num[len-1-i]=num[i]-num[len-1-i];
num[i]-=num[len-1-i];
}
int cnt=0;
for(int i=0;i<len;++i){
if(!num[i]){
++cnt;
continue;
}
if(!i){
if(len==1){
//cout<<"tem "<<haha<<" ret "<<ret<<endl;
return ret;
}
ret+=calc((1<<(len-1))-1);
//cout<<"1: "<<ret<<" "<<haha<<endl;
}
else{
ret+=help(len-i-1,len/2+len%2-cnt-1);
// cout<<len-i-1<<" "<<len/2+len%2-cnt-1<<" "<<help(len-i-1,len/2+len%2-cnt-1)<<endl;
// cout<<"2: "<<ret<<" "<<haha<<endl;
}
}
//cout<<"tem "<<haha<<" ret "<<ret<<endl;
return ret;
}
int main(){
set_c();
while(scanf("%d%d",&start,&finish)!=EOF){
long long ans=calc(finish)-calc(start-1);
cout<<ans<<endl;
}
return 0;
}