Description
序列 an a n 满足 a1=a2=1,an=an−an−1+an−1−an−2,n≥3 a 1 = a 2 = 1 , a n = a n − a n − 1 + a n − 1 − a n − 2 , n ≥ 3 ,给出一整数 n n ,求
Input
第一行一整数 T T 表示用例组数,每组用例输入一整数
Output
输出 ∑i=1nai ∑ i = 1 n a i
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
Solution
可以发现 a a 序列有两个规律,首先的值较 an−1 a n − 1 每次增加 0 0 或,其次,假设 an=2m⋅k,k a n = 2 m ⋅ k , k 为奇数,那么 an a n 在序列中出现 m+1 m + 1 次
以此规律,令 num[x] n u m [ x ] 表示前 x x 个自然数在该序列中出现的次数,表示在该序列中出现的前 x x 个自然数的和
对于~ x x 中的奇数,在序列中只出现一次,对于~ x x 中的偶数,把每个数字除以二则转化为求和 sum[⌊x2⌋] s u m [ ⌊ x 2 ⌋ ] ,由于 2k 2 k 出现次数比 k k 多一次,故有转移:
二分找到最大的 x x 满足,答案即为 sum[x]+(n−num[x])⋅(x+1) s u m [ x ] + ( n − n u m [ x ] ) ⋅ ( x + 1 ) ,时间复杂度 O(Tlog2n) O ( T l o g 2 n )
Code
#include<cstdio>
using namespace std;
typedef long long ll;
#define mod 1000000007
#define inv2 500000004
ll count(ll n)
{
if(n==1)return 2;
return n+count(n/2);
}
ll Solve(ll n)
{
if(n==1)return 1;
return (n%mod*((n+1)%mod)%mod*inv2%mod+2ll*Solve(n/2)%mod)%mod;
}
int main()
{
int T;
ll n;
scanf("%d",&T);
while(T--)
{
scanf("%I64d",&n);
if(n<=2)printf("%I64d\n",n);
else
{
ll l=1,r=1e18,pos,mid;
while(l<=r)
{
mid=(l+r)/2;
if(count(mid)<=n)pos=mid,l=mid+1;
else r=mid-1;
}
ll ans=(Solve(pos)+1)%mod;
ans=(ans+(n-count(pos))*(pos+1)%mod)%mod;
printf("%I64d\n",ans);
}
}
return 0;
}