E 牛牛的随机数 数位dp

E 牛牛的随机数
题解:思路就是算二进制每个位置的贡献,然后再将每个位置的贡献加起来就是总贡献。
关键是数位dp咋写;我看了半天就是唯一想不通的地方就是为啥要
lim == 0 时才能记忆化转移,同样才能给dp赋值。因为当lim==1时说明这个位置有限制所以你枚举的那个数位的数字可能就不是1,就可能多加贡献。所以需要没有限制的时候那么你枚举的数位必然可以达到1,所以可以无脑转移。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod = 1e9+7;
ll dp[100][100][2];
int a[100];
ll dfs(int pos,int k,int lim,int f)
{
    if(dp[pos][k][f]!=-1&&lim==0) return dp[pos][k][f];
    if(!pos) return 1LL*f;
    ll ans = 0;
    int up = lim?a[pos]:1;
    for(int i=0;i<=up;i++)
    ans += dfs(pos-1,k,lim&&i==up,f||pos==k&&i);
    return lim?ans:dp[pos][k][f] = ans;
}
ll div(ll x,int k)
{
    memset(a,0,sizeof(a));
    int pos = 0;
    while(x) { a[++pos] = x%2; x/=2; }
    return dfs(pos,k,1,0);
}
ll inv(ll x)
{
    ll ans = 1LL;
    ll tmp = mod - 2;
    while(tmp)
    {
      if(tmp&1) ans = ans*x%mod;
      x = x*x % mod;
      tmp/=2;
    }
    return ans;
}
int main()
{
    int T; scanf("%d",&T);
    memset(dp,-1,sizeof(dp));
    while(T--)
    {
        ll p =1LL,ans = 0;
        ll l1,r1,l2,r2; scanf("%lld%lld%lld%lld",&l1,&r1,&l2,&r2);
        for(int i=1;i<=60;i++,p*=2)
        {
            ll x , y;
            x = div(r1,i) - div(l1-1,i);
            y = div(r2,i) - div(l2-1,i);
            ans += ( ( x % mod ) *((r2-l2+1-y) % mod) % mod + (y%mod) * ( (r1-l1+1-x) % mod ) % mod ) * (p%mod) % mod;
            ans %= mod;
        }
   //     ans %= mod ; ans += mod ;
        ans %= mod;
        ans = ans * inv( (r2-l2+1)%mod * ( (r1-l1+1)%mod ) % mod) % mod;
        ans %= mod;
        printf("%lld\n",ans);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值