UVALive 6844 Combination

题目链接

题意:0 《= low《= high 《= 16 e11。比如low=2.high=3,求的是C【2】【0】,C[2][1],C【2】【2】。。C【3】【3】所有数中的奇数的个数。

题解:感觉就是只看C【i】【】的i就能够决定它的个数。打了个表,发现有重复的规律,从2的整次幂就会从头开始,但是数量会很多。于是再看1,23,4567,89101112131415,的和,发现是2,6,18,54.发现规律了!就是整次幂的就是前面的3倍。而且因为前面一半的都一样,那么其实是1+2的分布的。所以给出一个r,1~r的很好算。就是先搞出前面整的,然后最后一段:看是否长度大于一半,大于的话,先算出前面一半,然后加2倍的后面一半往前平移一段。log级别的就好了。长度小于一半的话直接就跑到前面的。这样就搞定了。0的情况特殊想下

重点:感觉出只由i应该就能决定,其次打表看发现有2幂次的小关系,再打和的表再发现出1+2的分布。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(ull i = a;i < b;i++)
#define REP_D(i, a, b) for(ull i = a;i <= b;i++)

typedef long long ll;
typedef unsigned long long ull;//llu

using namespace std;

const ull maxn = 40;
const double EPS = 1e-10;
ull d[maxn];
void getD()//整段的,i代表2的幂次
{
    d[0]=2;
    d[1]=6;
    d[2]=18;
    for(ull i = 3;i <= maxn-1;i++)
    {
        d[i]=d[i-1]*3;
        //printf("%d\n", d[i]);
    }
}
ull gao(ull s, ull n)//从2的s幂搞起,长度有n。其实就是分两种情况log往下分
{
    if(s==0)
    {
        return 2;
    }
    ull l = s-1;
    ull len = pow(2, l) + EPS;
    if(n <= len)
    {
        return gao(l,n);
    }
    else
    {
        return d[s-1]+2*gao(l,n-len);//2倍关系平移
    }
}
ull getAns(ull x)//这样算很好写。lr类型的都这样写
{
    if(x==0)
        return 0;
    if(x==1)
    {
        return 2;
    }
    if(x==2)
    {
        return 4;
    }
    ull k;
    for(ull i = 1;;i++)
    {
        if(pow(2,i)-EPS <= x)
        {
            k = i;
        }
        else
        {
            break;
        }
    }
    ull ans = 0;
    for(ull i = 0;i < k;i++)
    {
        ans += d[i];
    }
    ull start = (pow(2,k)+EPS);
    ull n = x - start + 1;
    ans += gao(k, n);
    return ans;
}
ull x, y;
void solve()
{
    ull ans = getAns(y) + 1;
    if(x!=0)
    {
        ans -= (getAns(x-1)+1);
    }
    printf("%llu\n", ans);
}
int main()
{
   // freopen("13Min.txt", "r", stdin);
    //freopen("1out.txt", "w", stdout);
    getD();
    while(scanf("%llu%llu", &x, &y) != EOF)
    {
        if(x==0&&y==0)
        {
            break;
        }
        solve();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值