Chiaki Sequence Revisited
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 493 Accepted Submission(s): 85
Problem Description
Chiaki is interested in an infinite sequence
a1,a2,a3,...).
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
Source
Recommend
题意: 给出一个数列的定义 ,要你求出数列的前n项和
多组询问最多1e5组 n为1e18
解题思路 :
其实是一个简单题。。。。
这种题先打表找下规律 ,
发现 对于每一个数 在数列中出现的次数x,为它最多能被2^(x-1)整除。
这样就很好写了,二分找出最后一个点是什么数。
然后分多个等差数列求和 求出总和 复杂度为lognlogn
但这样可能会超时
可以观察发现 a[n] 大概在n/2 附近 这样就能极大缩小二分范围。
最后代码只跑了400ms 还是很快的。
比赛的时候 由于中间变量写成int,加上在求等差数列和的时候手贱用快速幂求了逆元 导致没写出来
很亏。。。。。
7.24更新
今天早上把昨天比赛时候写的代码重看了一遍,把快速幂求逆元去掉就直接过了。。。。
直接从n/2 开始暴力找a[n]就行了,,,, 跑得也飞快。
比赛的时候真的浪费太多时间了
#include <bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
const int MAX = 1e5+7;
using namespace std;
const int MOD=1e9+7;
long long quick_pow(long long a,long long b){
long long ans=1;
while(b){
if(b&1){
ans=(ans%MOD*a%MOD)%MOD;
}
b/=2;
a=(a*a)%MOD;
}
return ans;
}
long long MOD2;
long long slove(long long n){
long long ans=0;
long long dis=1;
long long top;
while(dis<=n){
top=n/dis;
ans=(((dis%MOD+(top*dis)%MOD)%MOD*(top%MOD)%MOD*(MOD2)%MOD)%MOD+ans%MOD)%MOD;
//cout<<ans<<endl;
dis*=2;
}
return ans;
}
long long check(long long num){
long long nums=0;
while(num){
nums+=num;
num/=2;
}
return nums+1;
}
int main(){
MOD2= quick_pow(2,MOD-2);
int T;
cin>>T;
while(T--){
long long n;
scanf("%lld",&n);
if(n==1){
puts("1");
continue;
}else if(n==2){
puts("2");
continue;
}
long long top=n/2;
long long l=top-200,r=top+200,m;
while(l<=r){
m=(l+r)>>1;
if(check(m)>=n){
r=m-1;
top=m;
}else{
l=m+1;
}
}
long long ans;
if(check(top)==n){
ans=0;
}
else {
ans=top%MOD*(n-check(top-1))%MOD;
top--;
}
ans=(ans+slove(top))%MOD;
printf("%lld\n",(ans+1)%MOD);
//cout<<sum[n]<<endl;
}
}