%了dalao的博客,看了许久(菜是原罪),勉强看懂,不知是否有错,如有错欢迎指出。
等差数列
如下 下标,数值,和
///1 3 7 15 31 a[i]
///1 2 4 8 16 f[i]
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
const int mod = 1e9+7;
const int N = 105;
ll a[N], f[N];
int main()
{
int t;
ll pos, ans, n, m, num, now;
scanf("%d", &t);
a[0] = f[0] = 1;///a[i]对应f[i],idx->val
for(int i=1; i<=62; i++){///ll -> 2^64
a[i] = a[i-1]*2+1;
f[i] = f[i-1]*2;
}
ll inv = (mod+1)/2;///2的逆元
while(t --){
pos = ans = num = 0;
scanf("%lld", &n);
m = n;
for(int i=62; i>=0; i--){
if(m-a[i] >= 0){
m -= a[i];
pos += (1ll<<i);
}
}
pos += (m>0);///当前这位数字是多少
now = pos-1;///对当前数值之前的数处理,例pos=8,处理1~now这些数的和
ll s, step, e, sum;
for(int i=1; f[i-1]<=now; i++){
s = f[i-1];
step = (now-s)/f[i]+1;///项数
e = (step-1)*f[i]+s;///f[i]公差
sum = (s+e)%mod*(step%mod)%mod*inv%mod;///(start+end)*step/2
ans = (ans+sum*i%mod)%mod;///i这些数出现了几次
num += step*i;///算了多少个数
}
ans = (ans+1+(n-num-1)%mod*(pos%mod)%mod)%mod;///加上第一个数和其余未加的数
printf("%lld\n", ans);
}
}