HDU - 6304 Chiaki Sequence Revisited[2018杭电多校联赛第一场 G](找规律+位运算+逆元)

题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=6304

【题意】
给定一个序列a,定义a[1]=a[2]=1,a[n]=a[n-a[n-1]]+a[n-1-a[n-2]](n>=3),求该序列的前n项和是多少,结果对 1e9+7 取模

【输入格式】
第一行为数据组数T(T<1e5),下面T行每行一个整数n(n<1e18)

【输出格式】
每组数据输出一行,输出每个n对应的前n项和

【思路】
先打个表,大佬们说规律就是序列中的每个数字i会出现log[lowbit(i)]+1次,其中lowbit(i)=i&-i,我表示根本看不出来。然后可以发现
[1,1]中的所有数字出现了1次 1=2^1-1
[1,2]中的所有数字出现了3次 3=2^2-1
[1.4]中的所有数字出现了7次 7=2^3-1
[1,8]中的所有数字出现了15次 15=2^4-1
….
不只是这样,这些区间还可以相加,比如[1,1]和[1,4]合起来后[2,5]中的所有数字也是出现7次,然后就根据这样一个规律去二分n,找出已经出现完的a[n],然后去计算所有[1,a[n]]的数字和,再加上剩下的几项得到最终结果。计算和的时候又有一个等差数列的规律,比如算[1,15]的所有数字和,拆成若干个等差数列来计算
1 3 5 7 9 11 13 15 出现1次
2 6 10 14 出现2次
4 12 出现3次
8 出现4次
分别对每个等差数列求和,再乘以它出现的次数即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const ll mod=1e9+7;
const ll inv2=500000004; 

ll pw[80]; //pw[i]=2^i
ll cnt[80];//cnt[i]=2^(i+1)-1
ll n,pos;

void init(){//预处理 
    pw[0]=cnt[0]=1;
    for(int i=1;i<=62;++i){
        pw[i]=pw[i-1]*2;
        cnt[i]=2*pw[i]-1;
    }
}

ll getsum(ll p){//计算序列中出现的所有1,2...p的和 
    ll ans=0;
    for(ll i=1;i<=p;i*=2){
        ll num=(p-i)/(2*i); //首项=i, num=项数-1 
        ll last=i+num*(2*i);//公差是2*i, 算出末项 

        num=(num+1)%mod;//开始写成++num然后就WA了,简直要命 

        ll tmp=(i+last)%mod;//等差数列求和S=(首项+末项)*项数/2 
        tmp=tmp*num%mod;
        tmp=tmp*inv2%mod;

        tmp=tmp*(__builtin_ffsll(i))%mod;//乘以对应的出现次数
        //tmp=tmp*(__builtin_ctzll(i)+1)%mod;//等价写法

        ans=(ans+tmp)%mod; 
    }
    return (1+ans)%mod;//加上第一项被忽略的1 
}

int main(){
    init();
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%lld",&n);
        --n;
        if(0==n) { puts("1");continue; }
        pos=0;
        ll tmp=n;
        for(int i=62;i>=0;--i){//63的时候cnt会爆 
            if(tmp>=cnt[i]){
                tmp-=cnt[i];
                pos+=pw[i];
            }
        }

        ll ans=getsum(pos);
        if(tmp) ans=(ans+tmp%mod*(pos+1)%mod)%mod;//如果有剩下的几项,就再加上 
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2018-07-24 15:48  不想吃WA的咸鱼  阅读(116)  评论(0编辑  收藏  举报