2020牛客寒假算法基础集训营3——E.牛牛的随机数【数位DP】(待补)

题目传送门


题目描述

牛牛和牛可乐是一对好朋友,现在牛牛从值域[l1,r1]中随机给出一个数字a,牛可乐从值域[l2,r2]中随机给出一个数字b。问你 a b a\oplus b 的数学期望。其中 \oplus 为位运算符,表示按位取异或。

为了避免你输出的答案出现精度误差,请你输出一个分数 P Q 1 ( m o d    1 0 9 + 7 ) P*Q^{-1}(mod\,\, 10^9+7) ,其中 Q 1 Q^{-1} 表示在mod 条件下的乘法逆元。数据保证 g c d ( Q , 1 0 9 + 7 ) = 1 gcd(Q,10^9+7)=1 ,也就是说保证 Q 1 Q^{-1} 在该模条件下有意义,并且保证 ( r 1 l 1 + 1 ) ( r 2 l 2 + 1 ) (r_1-l_1+1)(r_2-l_2+1) 不是mod的倍数。


输入描述:

第一行是一个正整数 T ( 1 T 1 0 5 ) T(1 \leq T \leq 10^5 ) 表示有T组案例。

接下来T行,每行四个正整数 l 1 , r 1 , l 2 , r 2 ( 1 l 1 r 1 1 0 18 , 1 l 2 r 2 1 0 18 ) l_1,r_1,l_2,r_2(1 \leq l_1 \leq r_1 \leq 10^{18},1 \leq l_2 \leq r_2 \leq 10^{18})


输出描述:

请输出期望 P Q 1 ( m o d    1 0 9 + 7 ) P*Q^{-1}(mod\,\, 10^9+7)


输入

2
3 5 7 8
1 3 3 5


输出

500000011
222222228


说明

a可取3,4,5,b可取7,8

3 7 = 4 4 7 = 3 5 7 = 2 3\oplus7=4,4\oplus7=3,5\oplus7=2

3 8 = 11 4 8 = 12 5 8 = 13 3\oplus8=11,4\oplus8=12,5\oplus8=13

共6种情况,答案为 ( 4 + 3 + 2 + 11 + 12 + 13 ) / 6 = 45 / 6 = 15 / 2 = 15 2 1 ( m o d     1 0 9 + 7 ) = 15 500000004 % m o d = 500000011 (4+3+2+11+12+13)/6=45/6=15/2=15*2^{-1}(mod \,\,\, 10^9+7)=15*500000004\%mod=500000011


备注:

乘法逆元: Q 1 ( m o d    1 0 9 + 7 ) Q 1 0 9 + 5 Q^{-1}(mod\,\, 10^9+7)\equiv Q^{10^9+5}


题解

  • 首先答案为 x = l 1 r 1 y = l 2 r 2 x y ( r 1 l 1 + 1 ) ( r 2 r 2 + 1   )   \frac{\sum_{x=l_1}^{r_1}\sum_{y=l_2}^{r_2}x\oplus y}{(r_1-l_1+1)*(r_2-r_2+1\ )\ } ,就是枚举每种情况,然后除以方案总数。
  • 首先考虑二进制的个位产生的贡献,那么二进制个位产生的贡献有两部分:
  • [ l 1 , r 1 ] [l_1,r_1] 区间内个位为0的数字乘以 [ l 2 , r 2 ] [l_2,r_2] 区间内个位为1的数字。
  • [ l 1 , r 1 ] [l_1,r_1] 区间内个位为1的数字乘以 [ l 2 , r 2 ] [l_2,r_2] 区间内个位为0的数字。
    做一个二进制位的数位DP,用于统计该数位0与1的个数。
  • 假设 x [ l 1 , R 1 ] x \in [l_1,R_1] 中二进制的个位产生0的数目为 c n t x 0 cntx_0 二进制的个位产生1的数目为 c n t x 1 cntx_1
    y [ l 2 , R 2 ] y \in [l_2,R_2] 中二进制的个位产生0的数目为 c n t y 0 cnty_0 二进制的个位产生1的数目为 c n t y 1 cnty_1
    那么就产生了 c n t y 0 c n t x 1 + c n t x 0 c n t y 1 cnty_0 *cntx_1 +cntx_0 *cnty_1 的贡献。
  • 如果是二进制的十位呢,那么就是 ( c n t y 0 c n t x 1 + c n t x 0 c n t y 1 ) 2 (cnty_0 *cntx_1+cntx_0 *cnty_1 )*2
  • 那么二进制的第k位的贡献就为 ( c n t y 0 c n t x 1 + c n t x 0 c n t y 1 ) 2 k (cnty_0*cntx_1+cntx_0*cnty_1)*2^k
  • 不知道题解DP的是什么,待补

AC-Code

#include<bits/stdc++.h>
using namespace std;
const long long mod=(int)1e9+7;
int i,i0,T;
long long cnta[70],cntb[70],dp[70][70][2],a[70];
long long dfs(int len,bool maxi,int k,bool f)
{
    if(dp[len][k][f]!=-1&&maxi==0)return dp[len][k][f];
    long long cnt=0;
    if(!len)return f;
    int maxn=maxi?a[len]:1;
    for(int i=0;i<=maxn;i++)cnt+=dfs(len-1,maxi&&i==a[len],k,f||len==k&&i);
    return maxi?cnt:dp[len][k][f]=cnt;
}
long long div(long long tmp,int k)
{
    memset(a,0,sizeof(a));
    int p=0;
    while(tmp)a[++p]=tmp%2,tmp/=2;
    return dfs(p,1,k,0);
}
long long inv(long long x,long long mod)
{
    long long k=mod-2,ans=1;
    while(k)
    {
        if (k&1) ans=ans*x%mod;
        x=x*x%mod;
        k>>=1;
    }
    return ans;
}
int main()
{
    memset(dp,-1,sizeof(dp));
    scanf("%d",&T);
    while(T--)
    {
        long long l1,r1,l2,r2,p=1,ans=0;
        scanf("%lld %lld %lld %lld",&l1,&r1,&l2,&r2);
        l1--,l2--;
        for(i=1;i<=60;i++,p*=2)
        {
            cnta[i]=div(r1,i)-div(l1,i);
            cntb[i]=div(r2,i)-div(l2,i);
            ans+=(cnta[i]%mod*((r2-l2-cntb[i])%mod)%mod+cntb[i]%mod*((r1-l1-cnta[i])%mod)%mod)*(p%mod)%mod;
            ans%=mod;
        }
        ans%=mod,ans+=mod,ans%=mod;
        ans=ans*inv(((r1-l1)%mod)*((r2-l2)%mod)%mod,mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}
发布了167 篇原创文章 · 获赞 100 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Q_1849805767/article/details/104246337