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