把题目要求的写成下面的式子,其中
f
x
f_x
fx为
x
x
x的二进制中1的个数,lcp为最长公共前缀中1的个数。
A
N
S
=
∑
r
=
0
n
∑
l
=
0
n
(
f
l
+
f
r
−
2
f
l
c
p
(
l
,
r
)
)
2
ANS=\frac{\sum\limits_{r=0}^n \sum\limits_{l=0}^{n}(f_l+f_r-2f_{lcp(l,r)})}{2}
ANS=2r=0∑nl=0∑n(fl+fr−2flcp(l,r))
=
(
n
+
1
)
∑
r
=
0
n
f
r
−
∑
r
=
1
n
∑
l
=
1
n
(
f
l
c
p
(
l
,
r
)
)
= (n+1)\sum\limits_{r=0}^n f_r- \sum\limits_{r=1}^n \sum\limits_{l=1}^{n}(f_{lcp(l,r)})
=(n+1)r=0∑nfr−r=1∑nl=1∑n(flcp(l,r))
那我们先枚举每一个位置选算正贡献:设当前枚举到的位置为x,分两种情况:
1.高位都取到了最大值,那么 这一位必须能放1才有贡献,低位可以随便放。
2.高位没有都取到最大值,那么这一位就一定能放1,且低位可以随便放。
这样算出来的就是
∑
l
=
1
n
f
l
\sum\limits_{l=1}^nf_l
l=1∑nfl了。
那再算一下
∑
r
=
1
n
∑
l
=
1
n
(
f
l
c
p
(
l
,
r
)
)
\sum\limits_{r=1}^n \sum\limits_{l=1}^{n}(f_{lcp(l,r)})
r=1∑nl=1∑n(flcp(l,r)):
还是枚举每一位,分两种情况:
1.l,r的高位都取到了最大值,那么这一位必须能放1才可能有负贡献,l,r的低位都随便选。
2.l,r的高位相同且没有取到最大值,那么这一位必然能同时放1,l,r的低位还是随便选。
预处理一下n,就可以实现上述的操作。
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define wzh(x) cerr<<#x<<'='<<x<<endl;
int t,cas,bin[66];
LL n;
const int mod=1e9+7;
int mul(int x,int y){
return 1ll*x*y%mod;
}
int add(int x,int y){
x+=y;
if(x>=y)x-=mod;
if(x<0)x+=mod;
return x;
}
int fac[66];
int nxt[66],pre[66];
int main() {
ios::sync_with_stdio(false);
fac[0]=1;
for(int i=1;i<=60;i++)fac[i]=mul(fac[i-1],2);
for(cin>>t,cas=1;cas<=t;cas++){
cin>>n;int now=0;
for(LL x=n;x;x>>=1)bin[++now]=x%2;
//从低到高 [1,now]
for(int i=1;i<=now;i++)nxt[i]=add(nxt[i-1],mul(fac[i-1],bin[i]));
pre[now+1]=0;
for(int i=now;i>=1;i--)pre[i]=add(mul(2,pre[i+1]),bin[i]);
int ans=0;
for(int i=1;i<=now;i++){
if(bin[i]){
ans=add(ans,(nxt[i-1]+1));//高位为之前的最高位 pre[i+1]
}
ans=add(ans,mul(fac[i-1],pre[i+1]));//高位动 [0,pre[i+1])
}
ans=mul(ans,(n+1)%mod);
for(int i=1;i<=now;i++){
if(bin[i]){
ans=add(ans,-mul(nxt[i-1]+1,nxt[i-1]+1));
}
ans=add(ans,-mul(mul(fac[i-1],fac[i-1]),pre[i+1]));
}
cout<<"Case #"<<cas<<": "<<ans<<'\n';
}
return 0;
}