2018 Multi-University Training Contest 1 Chiaki Sequence Revisited 找规律

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
liuyiding   |   We have carefully selected several similar problems for you:   6308  6307  6306  6305  6304 
 

Statistic |  Submit |  Discuss | Note

题意: 给出一个数列的定义 ,要你求出数列的前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;
    }
}

猜你喜欢

转载自blog.csdn.net/lifelikes/article/details/81176252