HNU 2015暑期新队员训练赛2 B Combination

HNU 2015暑期新队员训练赛2 B Combination_第1张图片

先转化出求 Cnr中有多少奇数 其实就是 (n 的二进制数中 1 的个数为 k ,则这个奇数为 2 ^ k)

因为数很大, 故要快速求出区间的奇数

然后求 0 – low-1 的奇数, 0- high 的奇数 ,相减既是结果

求 0 – N 中 Cnr 的奇数

HNU 2015暑期新队员训练赛2 B Combination_第2张图片

通过上图可以快速求出 1 ---- (2^N)-1的个数,其他数则可以用迭代的方式求出来

(代码比赛写的有点残)

#include
#include
#include
#include<string>
#include
#include
#include
#include<set>
#include
#include
#include
//#include
using namespace std;
typedef __int64 LL;
typedef unsigned long long ULL;
const LL MOD = 1e7 + 7;
const LL maxn = 1e6 + 131;
ULL Num[4] = {1,3,5,9};
LL SumL = 0, SumR = 0;
ULL Pow(ULL a,ULL b)
{
    ULL ret = 1;
    while(b)
    {
        if(b & 1) ret = ret * a;
        a= a*a;
        b >>= 1;
    }
    return ret;
}
/*ULL GetSum(ULL low, ULL high)
{
    ULL sum = high - low + 1;
        for(ULL E = low; E <= high; ++E)
        {
            for(ULL r = 1; r <= E; ++r)
                if((E & r) == r) sum++;
        }
        printf("%I64u\n",sum);
}*/

int main()
{
    ULL low, high;
    while(scanf("%I64u%I64u",&low,&high) != EOF && (high + low))
    {
        SumL = 0, SumR = 0;
        //GetSum(low,high);
        ULL K = 0;
        if(low == 0) ;
        else {
            low --;
        if(low <= 3) SumL = Num[low];
        else {while(low > 3)
        {
            ULL cnt = 0;
            ULL tmp = low;  while(tmp) {cnt++, tmp >>= 1;}
            SumL += Pow((ULL)3,cnt-1) * Pow((ULL)2,K++);
            low -= Pow((ULL)2,cnt-1);
        } SumL += Num[low] * Pow((ULL)2,K);
        }
        }

        ////////////
        if(high ==0) ;
        else {
        if(high <= 3) SumR = Num[high];
        else {K = 0;
        while(high > 3)
        {
            ULL cnt = 0;
            ULL tmp = high;  while(tmp) {cnt++, tmp >>= 1;}
            SumR += Pow((ULL)3,cnt-1) * Pow((ULL)2,K++);
            high -= Pow((ULL)2,cnt-1);
        } SumR += Num[high] * Pow((ULL)2,K);
        }}
        cout << ULL(SumR-SumL) << endl;
    }
}

你可能感兴趣的:(HNU 2015暑期新队员训练赛2 B Combination)