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;
}