题目描述
我们知道,一个等差数列可以用三个数 A , B , N A,B,N A,B,N表示成如下形式:
B + A , B + 2 ∗ A , B + 3 ∗ A , . . . , B + N ∗ A B + A, B + 2 * A, B + 3 * A, ..., B + N * A B+A,B+2∗A,B+3∗A,...,B+N∗A
z t x z 16 ztxz16 ztxz16想知道对于一个给定的等差数列,把其中每一项用二进制表示后,一共有多少位是 1 1 1。
题目解析
一个类欧几里得的模板。
考虑二进制中第
k
k
k位的贡献
A
n
s
k
=
∑
i
=
1
n
[
A
i
+
B
的
第
k
位
为
1
]
=
∑
i
=
1
n
⌊
A
i
+
b
2
k
⌋
−
2
×
⌊
A
i
+
B
2
k
+
1
⌋
Ans_k=\sum_{i=1}^n [Ai+B的第k位为1]=\sum_{i=1}^n\lfloor \frac {Ai+b}{2^k}\rfloor -2\times \lfloor \frac {Ai+B}{2^{k+1}}\rfloor
Ansk=i=1∑n[Ai+B的第k位为1]=i=1∑n⌊2kAi+b⌋−2×⌊2k+1Ai+B⌋
然后就是类欧了
A n s k = f ( A , A + B , 2 k , n − 1 ) − 2 f ( A , A + B , 2 k + 1 , n − 1 ) Ans_k=f(A,A+B,2^k,n-1)-2f(A,A+B,2^{k+1},n-1) Ansk=f(A,A+B,2k,n−1)−2f(A,A+B,2k+1,n−1)
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll T,a,b,n,ans;
ll fun(ll n)
{
if(n&1) return (n+1)/2*n;
return n/2*(n+1);
}
ll f(ll a,ll b,ll c,ll n)
{
if(a==0) return (n+1)*(b/c);
if(a<c&&b<c)
{
ll m=(a*n+b)/c;
if(m==0) return 0;
return m*n-f(c,c-b-1,a,m-1);
}
return f(a%c,b%c,c,n)+fun(n)*(a/c)+(n+1)*(b/c);
}
int main()
{
cin>>T;
while(T--)
{
ans=0;
cin>>a>>b>>n;
for(ll i=1;i<=b+a*n;i+=i)
ans+=f(a,b+a,i,n-1)-f(a,b+a,i+i,n-1)*2;
cout<<ans<<endl;
}
}