[Jzoj] 3492. 数数

本文介绍了一种算法,用于计算等差数列中所有元素转换为二进制后1的数量。通过类欧几里得模板,文章详细解析了如何逐位计算贡献,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

我们知道,一个等差数列可以用三个数A,B,NA,B,NA,B,N表示成如下形式:

B+A,B+2∗A,B+3∗A,...,B+N∗AB + A, B + 2 * A, B + 3 * A, ..., B + N * AB+A,B+2A,B+3A,...,B+NA

ztxz16ztxz16ztxz16想知道对于一个给定的等差数列,把其中每一项用二进制表示后,一共有多少位是111

题目解析

一个类欧几里得的模板。

考虑二进制中第kkk位的贡献
Ansk=∑i=1n[Ai+B的第k位为1]=∑i=1n⌊Ai+b2k⌋−2×⌊Ai+B2k+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}}\rfloorAnsk=i=1n[Ai+Bk1]=i=1n2kAi+b2×2k+1Ai+B

然后就是类欧了

Ansk=f(A,A+B,2k,n−1)−2f(A,A+B,2k+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,n1)2f(A,A+B,2k+1,n1)

代码

#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;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值