Problem Description
Chiaki is interested in an infinite sequence a1,a2,a3,... , which is defined as follows:
An = A(n-A(n-1))+A(n-1-A(n-2));
Chiaki would like to know the sum of the first n terms of the sequence, i.e. ∑i=1nai . As this number may be very large, Chiaki is only interested in its remainder modulo (109+7 ).
Input
There are multiple test cases. The first line of input contains an integer T (1≤T≤105 ), indicating the number of test cases. For each test case:
The first line contains an integer n (1≤n≤1018 ).
Output
For each test case, output an integer denoting the answer.
Sample Input
10 1 2 3 4 5 6 7 8 9 10
Sample Output
1 2 4 6 9 13 17 21 26 32
思路: 首先打表后发现An数组中元素出现次数有规律可循。
即: 数 Ai 出现的次数为 Ai二进制后面0的个数加1。
题目中给定n,让求的是前n项和。假设知道An,那么
我们可以这样来求前n项和:
示例 :
1.2.3... An 首先出现了一次
2.4.6.8...Ai(Ai < An && Ai%2 == 0) 第二次出现。
4.8.12...Aj (Aj < An && Ai%4 == 0) 第三次出现。
...
最多也就枚举到 (1<<63)。而且每一行都是等差数列,求和没问题了。
这和求n!后面0的个数的算法思想是一致的。
那么问题是, An 怎么求 ?
考虑这两个问题 :
1. 给了n怎么求 An ?
2. 给了An怎么求 n ?
1问题明显就是我们想要的。
2问题则是可求的。
为什么呢 ? 由上面的示例可以知道给了An小与等于An的数出现的次数
都是可以求出来的。即:
An 项第一次出现
An/2 项重复出现一次
An/2/2重复出现二次。
。。。
那么小于等于An的数出现的次数和代表什么意思呢?
不就是n嘛?
(第一个1没考虑在内,特殊。。)
更确切一点说,应该是满足等于An的最后一个n,因为可能多个数等于An的。
说到这里二分一下就能求出An的值了。
还有一点不得不说,因为给定的n可能是连续的几个相同数字中中间的一个,因此
算结果的时候需要特别算一下。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 1e6+7;
ll mod2;
ll A[maxn];
ll check(ll An)
{
ll n = 0;
while(An)
{
n += An;
An /= 2;
}
return n+1;
}
ll qm(ll a, ll n)
{
ll ans = 1;
while(n)
{
if(n%2) ans=ans*a%mod;
a = a*a % mod;
n /= 2;
}
return ans;
}
int main()
{
int t;
mod2 = qm(2,mod-2);
scanf("%d",&t);
while(t--)
{
ll n;
scanf("%lld",&n);
if(n == 1)
{
printf("1\n");
continue;
}
if(n == 2)
{
printf("2\n");
continue;
}
ll An = 0;
ll l = n/2-200,r = n/2+200;
while(l <= r)
{
ll mid = (l+r) / 2;
if(check(mid) >= n)
{
An = mid;
r = mid-1;
}
else l = mid+1;
}
ll ans;
if(check(An) == n) ans = 0;
else{
ans = ((n-check(An-1))%mod)*(An%mod)%mod;
An--;
}
for(ll i = 1; i <= An; i<<=1)
{
ll tp = An / i;
ans += (i%mod*(tp%mod)+ (tp-1+mod)%mod*(tp%mod)%mod*(i%mod)%mod*mod2)%mod;//n*a1 + (n-1)*n/2
ans %= mod;
}
printf("%lld\n",(ans+1)%mod);
}
return 0;
}