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;
}
原文地址:https://www.cnblogs.com/VIrtu0s0/p/10812155.html