1. 程式人生 > >Codeforces Round #553 (Div. 2) C 等差數列求和 + 前綴和

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

求和 inline fin ons urn long long esp 計算 long

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;
}

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