zoukankan      html  css  js  c++  java
  • 0923考试T3 二进制,位运算

    0923考试T3

    ​ 题目描述:

    ​ 前方的地上散落着B朵樱花,此时刮起了风,便引来一场樱花雨。樱花雨一共持续了N秒。每一秒都会有A朵樱花飘落。小Q细心的记录了每一秒时间后地上樱花的数目,并将其转换成了二进制。小Q想请你统计一下这些二进制数一共有多少个1。

    (2 le N le 10 ^ 9, 1 le A le 10 ^ 4, 1 le B le 10 ^ {16})

    ​ 二进制,位运算。

    ​ 对于一个等差数列(b + a, b +2 * a, b + 3 * a,...,b+n * a), 第(i)项与第(2 ^ k + i)项的二进制下第(k)位是相同的。为啥呢?因为任何一个二进制,两个它相加相当于乘2,相当于左移一位,那那么第一位就为0了(假设没有第0位,从第一位开始编号),所以现在(k = 1)(b)(b + 2 ^ 1 * a)(1)位相同。

    ​ 先介绍一下(calc)函数,(calc(x, t))代表对于前(x)项,(2 ^ k = t),第(k - 1)位上有几个1。

    ​ 假设当前(k = 3),如果说第(i)项的后(k - 1)位小于100,对应这句:((b + a * i) \% t < (t >> 1)),那么这一项的第(k - 1)为肯定不为1。从((b + a * i) \% t)((t >> 1))中间的数肯定第(k - 1)位也不为0,那么直接跳就好了,跳的项数就是(((t >> 1) - (b + a * i) \% t - 1) / a)。下面$else $同理。

    ​ 主函数里那个循环:

    ​ 当(n >= i)时,(i)的含义有两个:前(i)项,(2^k = i),枚举到第(k)位。此时可以用上面那个定理,因为他有循环节,(b, b + 2^k, b +2^k + 2 ^ k...),它们的第(k)位都相同。此时我们只需要计算((n / i) * calc(i, i) + calc(n \% i, i))就好了。

    ​ 当(n >= i)时,(i)的含义只有(2^k = i),枚举到第(k)位。此时我们只要算(calc(n, i))就好了。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline long long read() {
        long long s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }
    
    long long a, b, n, T, ans;
    
    long long calc(long long x, long long t) {
        long long res = 0;
        // cout << x << " " << t << endl;
        for(long long i = 1;i <= x; i++) {
            if((b + a * i) % t < (t >> 1)) 
                i = min(x, i + ((t >> 1) - (b + a * i) % t - 1) / a);
            else {
                long long tmp = min(x, i + (t - (b + a * i) % t - 1) / a);
                res += tmp - i + 1; i = tmp;
            }
        }
        return res;
    }
    
    int main() { 
    
        freopen("flowers.in","r",stdin); freopen("flowers.out","w",stdout);
    
        T = read();
        while(T --> 0) {
            ans = 0;
            a = read(); b = read(); n = read();
            for(long long i = 2;i < ((b + a * n) << 1); i <<= 1) {
                if(n / i) ans += 1ll * (n / i) * calc(i, i);
                ans += calc(n % i, i);
            }
            printf("%lld
    ", ans);
        }
    
        fclose(stdin); fclose(stdout);
        return 0;
    }
    
    /*
    2
    7 4 1
    5 8 2
    
    2
    2 4 5
    5 9 5
    */
    
  • 相关阅读:
    [转载] c++ cout 格式化输出浮点数、整数及格方法
    [转]
    _jobdu_1001
    关于网页授权的两种scope的区别说明
    CentOS编译安装Python3
    Apache+OpenSSL实现证书服务器提供HTTPS
    Linux下安装Tomcat服务器和部署Web应用
    记一次肉机事件--yam
    通过关闭 UseDNS和GSSAPIAuthentication选项加速 SSH登录
    Git 系列之tag的用法---为你的代码标记版本号
  • 原文地址:https://www.cnblogs.com/czhui666/p/13726765.html
Copyright © 2011-2022 走看看