题解 CF1151C 【Problem for Nazar】
\[\huge\mathcal{DESCRIPTION}
\]
日期 | 2020年8月24日 |
---|---|
编号 | \(\texttt{CF1151C}\) |
算法 | 数学、差分 |
来源 | 无名小题 |
\[\huge\mathcal{SOLUTION}
\]
设黑板上的序列为\(A_1,A_2,\ldots\)
则题目求的是:
\[\sum_{i=Left}^{Right}A_i
\]
我们容易想到差分:
\[\sum_{i=Left}^{Right}A_i
=\sum_{i=1}^{Right}A_i-\sum_{i=1}^{Left-1}A_i
\]
这里需要用到两个公式:
- 奇数序列的前\(k\)项和为\(k^2\)
- 偶数序列的前\(k\)项和为\(k^2+k\)
所以我们只需要知道有多少个奇数,多少个偶数,就可以用\(\mathcal O(1)\)的时间复杂度求出和。
考虑如何求项数?
因为每次奇数和偶数都是\(2^k\)个元素拼接而成的。
所以我们可以在\(\mathcal O(logN)\)的时间内计算出两个数列的元素个数。
然后就\(AC\)了\(\ldots\)
\[\huge\mathcal{CODE}
\]
#include<bits/stdc++.h>
#define MOD 1000000007
using namespace std;
inline long long Sum(long long Length)
{
register long long i;
register long long Len1,Len2;
Len1=Len2=0;
register long long Log;
Log=log2(Length+1LL);
for(i=0;i<Log;i++)
{
if(!(i&1))
{
Len1+=(1LL<<i);
Len1%=MOD;
}
else
{
Len2+=(1LL<<i);
Len2%=MOD;
}
}
register long long Other;
Other=Length-(1LL<<Log)+1LL;
Other%=MOD;
if(!(Log&1))
{
Len1+=Other;
Len1%=MOD;
}
else
{
Len2+=Other;
Len2%=MOD;
}
return (Len1*Len1%MOD+Len2*(Len2+1)%MOD+MOD)%MOD;
}
int main(void)
{
register long long Left,Right;
cin>>Left>>Right;
cout<<(Sum(Right)-Sum(Left-1)+MOD)%MOD<<endl;
return 0;
}
不要妄图追上西坠的太阳,而是要在黎明前就等着它!