题解:
先把数列a打表找一下规律,发现(除了第一项1以外):
出现1次:1,3,5,7,9,11,13,15......
出现2次:2,6,10,14,18,22,26......
出现3次:4,12,20,28,36,44......
出现4次:8,24,40,56,72,88......
可以总结为:
每个分类都是等差数列
第i个分类的首项是,公差为
根据n,二分出前n项中出现的数字的种数为x,然后根据以上规律,和等差数列的通项公式,求出前n项和。
例如:
n为9时,二分出x为5,即出现了数字1,2,3,4,5,然后根据出现的次数求和为:1+3+5+2*2+4*3+1=26.
代码:
#include<bits/stdc++.h>
#define N 100010
#define INF 0x3f
#define LL long long
#define eps 1e-8
using namespace std;
const LL inv2=5e8+4;
const LL P=1e9+7;
LL sum(LL x)
{
LL num=0;
for (int i=1;i<63;i++) num+=((x+(1ll<<(i-1)))>>i)*i;
return num;
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
LL T;
cin>>T;
while(T--)
{
LL n;
cin>>n;
if (n==1)cout<<1<<endl;else if (n==2)cout<<2<<endl;else if (n==3)cout<<4<<endl;else
{
LL l=max(1ll,n/2-50),r=min(n,n/2+50);
LL ans=0;
while(r-l>1)
{
LL t=(l+r)>>1;
if (sum(t)+1<=n) {ans=t;l=t;}
else r=t;
}
LL m=sum(ans)+1;
m=n-m;
LL A=0;
for (int i=1;i<=61;i++)
{
LL num=((ans+(1ll<<(i-1)))>>i)%P;
LL a1=(1ll<<(i-1))%P;
A=(A+ (a1*num%P + (((num*((num-1+P)%P))%P)*inv2%P)*((1ll<<i)%P)%P ) *i%P )%P;
}
for (int i=1;i<=m;i++) A=(A+ans+1)%P;
cout<<(A+1)%P<<endl;
}
}
return 0;
}