您的位置:首页 > 其它

uva 11645 Bits

2013-01-14 23:03 302 查看

uva 11645 Bits

题目描述:一个数n的二进制表示中连续的11的个数记为f(n),例如f(111) = 2, f(1111) = 3,先给定n求ans = sum (f(i)) 0=<i <= n;

解决办法:逐位确定

举例说明:n = 1111, x1 = 11**, x2 = *11*, x3 = **11

所以答案可以分成如下3个部分,即前两位是11的个数,中间两位是11的个数,后两位是11的个数。

首先对于前两位是11的个数,也即x1情况下,此时,满足条件的数由后两位确定,所以一共有4个(0~11)

然后对于中间两位是11的个数,这个时候后面的取值受限于第一位,

但是我们可以分成两种情况来计算,前面的部分是小于n的对应位的也即取0,此时后面1位有2中取值方式,故有1*2个数;前面的部分刚好与n的对应部分相等即取1,此时后面只有0~1(1为n的最后几位的值)所以此时有:1 + 1个数, 此种情况下共有4个

最后对于后两位是11的个数,这个时候只取决于n的前两位的取值,所以有4种

综上3种情况,共有4+4+4 = 12

再看对于n = 11011:

同样可以分成x1 = 11***, x2 = *11**,x3 = **11*, x4 = ***11

计算x1:满足x1的情况只有011 + 1种,即:4种

计算x2: 满足x2的情况可以分成,前面的部分小于n对应位,此时只能取0,后面有2^2种取法,所以有4种,而对于前面部分等于n对应位,此时得到的数已经超过了11011所以此时是不存在的,故满足x2的共有4种

计算x3:同情况2,拆分成两个部分,前面两位小于11011的前两位,此时前面有3(0~11-1)种取法,后面可以取2^1种,故有3*2 = 6种;

前面两位与11011的前两位相等,由于已经超过原数,不存在

计算x4:由于最后两位和原数的最后两位一样,所以有110 + 1种取法,故而有7种取法

综上4种情况共有4 + 4 + 6 + 7 = 21。

归纳起来:对于位置i和i-1如果都为1,那么可以分成两部分:

l * 2^(i - 1) l = n>>i;

如果原数的i和i-1位都是1,那么返回,r + 1, r = n%(1<<(i-1));否则返回0

然后就是大数,只需要大数加。

最近写代码写的比较少,思维比较卡,代码写的比较搓。。。。。。在UVA上跑了,0.008s。。。。。。再优化一下,说不定可以跑到第一。。。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
LL f[65];
const int base = 10000;

class bigInt{
private:
int s, num[10];
public:
bigInt();
bigInt(LL );
friend bigInt operator+(const bigInt&, const bigInt &);
void print()const ;
};

bigInt::bigInt(){
s = 1;
memset(num, 0, sizeof(num));
}

bigInt::bigInt(LL x){
s = 0;
memset(num, 0, sizeof(num));
if(x==0)
s = 1;
while(x){
num[s ++] = x%base;
x = x/base;
}
}

bigInt operator+(const bigInt &op1, const bigInt &op2){
bigInt r;
r.s = op1.s > op2.s ? op1.s : op2.s;
for(int i = 0; i < r.s; i ++){
r.num[i] = r.num[i] + op1.num[i] + op2.num[i];
r.num[i + 1] = r.num[i]/base;
r.num[i] = r.num[i]%base;
}
while(r.num[r.s]){
r.num[r.s + 1] = r.num[r.s]/base;
r.num[r.s] = r.num[r.s]%base;
r.s ++;
}
return r;
}

void bigInt::print()const{
printf("%d", num[s - 1]);
for(int i = s - 2; i >= 0; i --){
printf("%04d", num[i]);
}
printf("\n");
}

void init(){
f[0] = 1;
for(int i = 1; i != 64; i ++){
f[i] = f[i - 1] + f[i - 1];
}
}

int main(){
init();
int cas = 0;
LL K, left, right;
bigInt ans;
ios::sync_with_stdio(false);

while(cin>>K, K >= 0){
int i;
for(i = 63 ; i >= 0; i --){
if(K&f[i]){
break;
}
}
left = 0, right = K;
ans = 0;

if(K&f[i]){
right = K - f[i];
}
if(K&f[i - 1]){
right = right - f[i - 1];
}

if((K&f[i]) && (K&f[i-1])){
ans = right + 1;
}
i --;
while(i > 0){
left = left + left;
left = left + ((K>>(i + 1))&1);
if(K&f[i - 1]){
right = right - f[i - 1];
}
if((K&f[i]) && (K&f[i-1]) ){
ans = ans + left * f[i-1] + right + 1;
}
else{
ans = ans + left * f[i-1];
}
i --;
}
printf("Case %d: ", ++cas);
ans.print();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: