Codeforces Round #553 (Div. 2) C 等差数列求和 + 前缀和

https://codeforces.com/contest/1151/problem/C

题意

有两个等差数列(1,3,5,..),(2,4,6,...),两个数列轮流取1,2,4,...,\(2^n\)组成一个新的数列,然后询问区间l,r的和

题解

  • 一开始总想着怎么计算中间那一段,其实用前缀和很好处理
  • 数太大,第二个数也要取模才能相乘

代码

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
const ll cha=2;
const ll P = 1e9+7;
ll pw(ll bs,ll x){
    ll ans=1;
    while(x){
        if(x&1)ans*=bs;
        bs*=bs;
        x>>=1;
    }
    return ans;
}

ll pw(ll bs,ll x,ll MOD){
    ll ans=1;
    while(x){
        if(x&1)ans=ans*bs%MOD;
        bs=bs*bs%MOD;
        x>>=1;
    }
    return ans;
}
const ll pw2=pw(2,P-2,P);

ll cal(ll x){
    ll i=1;int odd=1;
    ll od=1,ed=2,d,lt;
    ll ans=0;
    while(x>=pw(2,i-1)){
        //cout<<i<<" "<<ans<<endl;
        //cout<<od<<" "<<ed<<endl;
        x-=pw(2,i-1);
        d=pw(2,i-1);
        if(odd){
            ans+=(od%P*(d%P)%P+d%P*((d-1)%P)%P)%P;
            ans%=P;
            od+=d*cha;
        }else{
            ans+=(ed%P*(d%P)%P+d%P*((d-1)%P)%P)%P;
            ans%=P;
            ed+=d*cha;
        }
        odd^=1;
        i++;
    }
    //cout<<i<<endl;
    //cout<<ans<<endl;
    if(x==0)return ans;
    d=x;
    if(odd){
            ans+=(od%P*(d%P)%P+d%P*((d-1)%P)%P)%P;
            ans%=P;
            od+=d*cha;
        }else{
            ans+=(ed%P*(d%P)%P+d%P*((d-1)%P)%P)%P;
            ans%=P;
            ed+=d*cha;
        }    
    return ans; 
}
        

int main(){
    ll l,r;
    cin>>l>>r;
    cout<<(cal(r)-cal(l-1)+P)%P;
}

猜你喜欢

转载自www.cnblogs.com/VIrtu0s0/p/10812155.html