链接:https://ac.nowcoder.com/acm/contest/889/I
来源:牛客网
题目描述
输入N个M求
((KM)&M)mod(1e9+7)
输入描述:
The first and only line of input contains two space-separated integers, N, M (1 <= N <= 10^18, 1 <= M <= 10^11).
输出描述:
Output a single integer, the answer to the problem.
示例1
输入
4 6
输出
12
说明
The sum is 6 + 4 + 2 + 0 = 12.
题解:
算M每一个二进位上的贡献度,假设M二进制的第j位是1,假设 1M,2M,3M....NM中有x个数字第j位是1.
那么第j位二进制的贡献度就是 (1<<j)*x
那么现在的问题就是怎么能快速的求出1M,2M,3M....NM中有多少个数字第j位二进制是1
假设iM的二进制的第j位的求法为:
然后可以用类欧几里得分别算出等差数列的这两项之和。
参考博客:https://blog.csdn.net/WorldWide_D/article/details/54730588
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod= 1e9 + 7;
const long long inv2=(mod+1)/2;
ll f(ll a,ll b,ll c,ll n){
if (!a) return 0;
ll x,y;
if(a>=c||b>=c){
x=f(a%c,b%c,c,n);
y=((a/c)%mod*(n%mod)%mod*((n+1)%mod)%mod*inv2+b/c%mod*((n+1)%mod)+x)%mod;
y=(y+mod)%mod;
return y;
}
ll m=((__int128)a*n+b)/c;
x=f(c,c-b-1,a,m-1);
y=((__int128)n*m-x)%mod;
y=(y+mod)%mod;
return y;
}
int main(){
ll n,m;
cin>>n>>m;
ll ans=0;
for(int i=0;i<40;i++){
if(m>>i&1){
ll t=f(m,0,1LL<<i,n)-2*f(m,0,2LL<<i,n);
t=(t%mod+mod)%mod;
ans=(ans+(1LL<<i)%mod*t%mod)%mod;
}
}
printf("%lld\n",ans);
return 0;
}