[Jzoj] 3492. 数数

题目描述

我们知道,一个等差数列可以用三个数 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+2A,B+3A,...,B+NA

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=1n[Ai+Bk1]=i=1n2kAi+b2×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,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;
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值