F题题解:

大致思路:

先看操作成功的规律:

对于一个 ,按二进制来看 最低位(即 lowbit)加进 中,会变为 ,并进位,而更低位的值不会变化。下一次 最低位 将会变高,而当 最低位比 最高位还高时, 的值将不会发生变化。

举个例子: 如果 (二进制表示)

  1. 第一次操作:

  2. 第二次操作:

  3. 第三次操作:

之后 的值将不再变化。

二进制最高 位,故 最多变化 次。

我们只需求出小于等于 次变化的概率;

然后用 减掉前面的概率,算出大于等于 次变化的概率(对应的 都相等)。

用概率乘上对应的 即可算出总期望。

变化 次的概率为:

使用快速幂计算逆元与 的幂次。

时间复杂度

最终代码:

#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();}