题解 UVa11645

题目大意 多组数据,每组数据给定一个正整数 \(n\),请求出 \(\sum_{i=0}^n A(i)\),其中 \(A(n)\)\(n\) 的二进制表示中连续两个 \(1\) 出现的个数(比如 \(A(6_{10})=A(110_2)=2,A(15_{10})=A(1111_2)=3\)),输入以负整数结尾。

分析 正面统计很难做,所以我们从反面来统计每组相邻的 \(1\) 会给答案做出多少贡献。不难发现,这两位做出的贡献就是其在二进制表示下前面的部分加上一个零头。而这个零头仅在这两位本来就是 \(1\) 的时候才会出现,且就是这两位后面的部分(比如 \(11101_2\) 中第 \(3,4\) 两位的贡献为 \((11000+0)_2\)\(2,3\) 位的贡献为 \((10000+01)_2\))。

比较恶心的是这道题输入不是以 \(-1\) 结尾,而是负整数,且最大的数据会爆 long long,只能手写高精度或使用 __int128

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

int t;
__int128 n, x, now, ans;


__int128 Read()
{
    __int128 x = 0, op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9') {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9') {
        x = (x << 3) + (x << 1) + ch - '0';
        ch = getchar();
    }
    return x * op;
}

void Print(__int128 x)
{
    if(x < 0) putchar('-1'), x = -x;
    if(x > 9) Print(x / 10);
    putchar(x % 10 + '0');
}

int main()
{
    while((n = Read()) >= 0) {
        ans = 0, now = 0, x = n;
        while(x) {
            ans += ((__int128)1 << now) * (x >> 2) + (x & 1 && x & 2) * (n % ((__int128)1 << now) + 1);
            x >>= 1, ++now;
        }
        printf("Case %d: ", ++t);
        Print(ans), putchar('\n');
    }
}

猜你喜欢

转载自www.cnblogs.com/whx1003/p/12323367.html