CF1151C Problem for Nazar

CF1151C Problem for Nazar - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目并没有给出 \(r - l\) 的限制,这意味着 \(l = 1, r = 10^{18}\) 的查询也需要在我们能处理的范围之内。

那可放心差分:第 \(l\) 个数到第 \(r\) 个数所有和,就是前 \(r\) 个数的和减去前 \(l - 1\) 个数的和。前缀和一般都比区间和好处理。

\(r\) 个数一定可以拆分为两个子序列:一个长度为 \(p\) 的从 \(1\) 开始的连续奇数序列;一个长度为 \(q\) 的从 \(2\) 开始的连续偶数序列。

简单的数学知识可以推导得答案为 \(p^2 + q^2 + q\)。那么问题变成求解 \(p\)\(q\)

根据题意,把 \(r\) 分解为 \(2^0 + 2^1 + 2^2 + \cdots + 2^k +c\)。这个式子里,奇数项之和就是 \(p\),偶数项之和就是 \(q\)

朴素的 \(\log r\) 分解就可以了。

时间复杂度 \(\mathcal{O}(\log r)\)

/*
 * @Author: crab-in-the-northeast 
 * @Date: 2022-10-17 16:42:44 
 * @Last Modified by: crab-in-the-northeast
 * @Last Modified time: 2022-10-17 16:50:53
 */
#include <bits/stdc++.h>
#define int long long

const int mod = (int)1e9 + 7;

inline int read() {
    int x = 0;
    bool flag = true;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-')
            flag = false;
        ch = getchar();
    }
    while (isdigit(ch)) {
        x = (x << 1) + (x << 3) + ch - '0';
        ch = getchar();
    }
    if(flag)
        return x;
    return ~(x - 1);
}

inline int solve(int n) {
    int p = 0, q = 0, t = 1;
    for (int s = 1; s <= n; s <<= 1, t ^= 1) {
        n -= s;
        if (t)
            (p += s) %= mod;
        else
            (q += s) %= mod;
    }

    if (t)
        (p += n) %= mod;
    else
        (q += n) %= mod;
    
    return (((p * p % mod + q * q % mod) % mod) + q) % mod;
}

signed main() {
    int l = read(), r = read();
    printf("%lld\n", (solve(r) - solve(l - 1) + mod) % mod);
    return 0;
}
posted @ 2022-10-17 16:55  dbxxx  阅读(22)  评论(0编辑  收藏  举报