hdu 6304

(找规律)
题意:
  给定一个数列,以及 T T ( T<105 T < 10 5 )个询问。每个询问包含一个数字 n n ( n<1018 n < 10 18 ),输出这个数列的前 n n 项和。

hdu 6304_第1张图片

思路:
  先打表,看看 an a n Sn S n (将数列的前n项和记为 Sn S n )有什么规律。
   n n : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
   an a n : 1, 1, 2, 3, 3, 4, 4, 4, 5, 6
   Sn S n : 1,2,4,6,9,13,17,21,26,32
  观察到 an a n 中的数字是连续出现的,但是每个数字出现次数不同。这时找不到 an a n 数字出现次数和n的关系。但是发现 an a n 出现次数和自身这个数字有关: an a n 出现的次数等于 an a n 的lowbit值的位数。(比如3,它的二进制是1 1,lowbit只有一位,故3出现一次)。
  这样一来,虽然给定 n n 的值,我们不能找到 an a n ,但是反过来是可以运算的。举例而言,假如 an a n 为5, n n 的值就是 (log(lowbit(i))+1) ∑ ( l o g ( l o w b i t ( i ) ) + 1 ) (通过枚举 lowbit(x) l o w b i t ( x ) 的值来求解)。知道这个以后,我们可以准确估计一下 an a n 的上下界,然后通过二分求得 an a n 。时间复杂度: O(Klog(n)) O ( K ∗ l o g ( n ) )
   求出 an a n 后,就想办法求 Sn S n ,由于 an a n 之前的数字肯定小于等于 an a n ,并且是连续出现。我们就可以想办法将这个数列拆成 k k 个子数列,进而再求和。其中第 i i 个子数列中的数字的 lowbit l o w b i t 值都是 i i 。时间复杂度: O(log(n)) O ( l o g ( n ) )
   总时间复杂度: O(Klog(n)) O ( K ∗ l o g ( n ) )

关键点:
  想到如何快速找到 an a n 的值。

代码:

#include 
#include 
#define LL long long

using namespace std;

const LL mod = 1000000007;
const LL inv2 = 500000004;

LL get_idx(LL num) {
    LL ret = 0, x = num;
    for (LL i=0; (1LL<1) * ((x+1)>>1);
        x /= 2;
    }
    return ret;
}

LL get_sum(LL num) {
    LL ret = 0;
    for (LL i=0; (1LL<1LL<> (i+1)) + 1;
        LL fst = (1LL<1) << (i+1));
        LL incre = (i+1) * ((fst + lst) % mod) % mod * (n_term % mod) % mod * inv2 % mod;
        //ret += (i+1) * (fst + lst) * n_term / 2;
        ret = (ret + incre) % mod;
    }
    return ret;
}

int main() {
    //freopen("in.txt", "r", stdin);
    LL n, T;
    scanf("%lld", &T);
    while (T --) {
        scanf("%lld", &n); n --;
        LL l = max(n/2-50, 1LL), r = n/2+50;
        while (l < r) {
            LL mid = (l+r) / 2, idx = get_idx(mid);
            if (idx < n) l = mid + 1;
            else r = mid;
        }
        LL sum = get_sum(l), cur_idx = get_idx(l);
        LL offset = l % mod * (cur_idx - n) % mod;
        LL ans = (sum - offset + mod + 1) % mod;
        printf("%lld\n", ans);
    }
    return 0;
}

你可能感兴趣的:(数学推导)