2019牛客暑期多校9I:KM and M【类欧几里得模板】

题目:

2019牛客暑假多校9I:KM and M

题意:

输入N,M,求下列式子的值:

笔记:

考虑对M的每一位算贡献,假设M的第x位为1,那么计算这一位的贡献就等价于计算KM中有多少个数的第x位为1,计算一个数第x位的值是多少可以这样计算:(v>>x) - (v>>(x+1))*2,那么第x位的贡献为:

=2^x\sum_{k=1}^{N}\left \lfloor \frac{km}{2^x} \right \rfloor-2\left \lfloor \frac{km}{2^{x+1}} \right \rfloor

=2^x(\sum_{k=1}^{N}\left \lfloor \frac{km}{2^x} \right \rfloor-2\sum_{k=1}^{N}\left \lfloor \frac{km}{2^{x+1}} \right \rfloor)

上面求和式就是类欧几里得的模板

类欧几里得的详细讲解

代码:

#include <bits/stdc++.h>

using namespace std;
typedef __int128 LL;
const int mod = 1e9+7;
const int inv2 = 500000004;
inline LL read(){
    LL x = 0,f = 1; char c = getchar();
    while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+(c-'0');c = getchar();}
    return x*f;
}
inline void write(LL x){
    if(x < 0) putchar('-'),x = -x;
    if(x > 9) write(x/10);
    putchar(x%10+'0');
}
LL solve(LL a,LL b,LL c,LL n){         //计算(a*0+b)/c+(a*1+b)/c+...+(a*n+b)/c
    if(a == 0) return b/c%mod*(n+1)%mod;
    if(a>=c || b>=c) return solve(a%c,b%c,c,n)+n%mod*(n+1)%mod*inv2%mod*(a/c)%mod+(n+1)%mod*(b/c)%mod;
    LL m = (a*n+b)/c;
    return (n%mod*m%mod-solve(c,c-b-1,a,m-1)+mod)%mod;
}
int main(){
    LL n,m,ans = 0;n = read(),m = read();
    for(int i = 0;i < 50;++i){
        if(m&(1ll<<i)){
            ans += (1ll<<i)%mod*(solve(m,0,1ll<<i,n)%mod-2ll*solve(m,0,1ll<<(i+1),n)%mod+mod)%mod;
            if(ans >= mod) ans -= mod;
        }
    }
    write((ans%mod+mod)%mod);
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值