等比数列求和(倍增法)

题目大意:给定n,l,ri=lrni其中2<=n<=109;1<=l,r<=1018

总之就是求和公式不可用问题
1. 提公因式nl,原式变为nli=0rlni
2. log2l求出nl
3. 方便起见,我们定义自然数集上的函数f(i)=f2(i1)f(0)=1,f(1)=n以及h(i)=h(i1)(f(i)+1)h(0)=1,定义变量len=rl+1
4. 对于i=0len1ni,我们隔一个数提一次公因式,得到(n+1)i=0len12n2i
5. 以此类推,我们得到len=2k时,i=0len1ni=i=0k1(n2i+1)
6. 特殊地,当len=1时,有i=0len1ni=1显然成立
7. 我们通过画图发现,求和得到的ans其实与len的二进制位相关
8. 通过更进一步观察,我们得到如下结论:ans需要进行一次求和,当且仅当len二进制位当前位为1
9. 再结合之前提公因式得到的结论,我们得到anslen倒数第k位为1时需要同h(k1)·f(k)len2k11求和
10. 对于f(x)h(x)我们可以在O(60)的复杂度内完成预处理
11. 于是我们就得到了这份时间复杂度最差为O(3600)的代码

void solve2(){
    n%=MOD;
    a[0]=b[0]=1;
    a[1]=n;
    for(int i=2;i<=60;++i) a[i]=a[i-1]*a[i-1]%MOD;
    for(int i=1;i<=60;++i) b[i]=b[i-1]*(a[i]+1)%MOD;
    long long ans=0,w=n,pw=1;
    r=r-l+1;
    while(l){
        if(l&1) pw=pw*w%MOD;
        l>>=1,w=w*w%MOD;
    }int t=0;
    while(r){
        if(r&1){
            long long y=r-1,q=1;w=a[t+1];
            while(y){
                if(y&1) q=q*w%MOD;
                y>>=1,w=w*w%MOD;
            }ans=(ans+q*b[t])%MOD;
        }r>>=1,++t;
    }printf("%lld\n",ans*pw%MOD);
}
阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页