F题题解:
大致思路:
先看操作成功的规律:
对于一个 和
,按二进制来看
的
最低位(即 lowbit)加进
中,会变为
,并进位,而更低位的值不会变化。下一次
的
最低位 将会变高,而当
的
最低位比
的
最高位还高时,
的值将不会发生变化。
举个例子: 如果 (二进制表示)
-
第一次操作:
-
第二次操作:
-
第三次操作:
之后 ,
的值将不再变化。
二进制最高
位,故
最多变化
次。
我们只需求出小于等于 次变化的概率;
然后用 减掉前面的概率,算出大于等于
次变化的概率(对应的
都相等)。
用概率乘上对应的 即可算出总期望。
变化 次的概率为:
使用快速幂计算逆元与 的幂次。
时间复杂度 。
最终代码:
#include<bits/stdc++.h>
#define ll long long
#define MO 1000000007ll
#define MXN 1000002
using namespace std;
inline void rd(ll &x){x=0;short f=1;char c=getchar();while((c<'0'||c>'9')&&c!='-') c=getchar();if(c=='-') f=-1,c=getchar();while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();x*=f;}
ll T=1,n,m,k,a[MXN],ans;
ll p[32];
ll ksm(ll a,ll b){
ll s=1;
while(b){
if(b&1) s*=a,s%=MO;
a*=a,a%=MO;
b>>=1;
}
return s;
}
ll cal(ll n,ll m){//求组合数
ll ans=1;
for(ll i=1,j=n-m+1;i<=m;i++,j++)
ans*=j*ksm(i,MO-2)%MO,ans%=MO;
return ans;
}
void solve(){
rd(n),rd(m),rd(k);
for(ll i=0;i<=30;i++)
p[i]=cal(k,i)*ksm(ksm(2,k),MO-2)%MO,
p[31]+=MO-p[i];
p[31]=(1+p[31])%MO;
for(ll i=1,x;i<=n;i++){
rd(x);
for(ll j=0;j<=31;j++){
ans+=x*p[j]%MO,ans%=MO;
x+=x&m;
}
}
pt(ans);
}int main(){while(T--) solve();}