1 条题解

  • 0
    @ 2026-7-18 23:05:11

    传送门

    题意:求LxyRL\leq x\leq y\leq R且满足y%x=yxy\% x=y\oplus x(x,y)(x,y)的对数。(1LR1018)(1\leq L\leq R\leq 10^{18})

    y%xy\% x显然很不好做,我们需要转化一下。

    我们发现:

    1.1.2xy2x\leq y,有yx>y%xy-x>y\% x

    2.2.2x>y2x>y,有yx=y%xy-x=y\%x

    3.3. yxyxy\oplus x\geq y-x

    于是:

    2xy2x\leq y时,不存在yx=y%xy\oplus x=y\% x

    所以2x>y2x>y,即xxyy的位数相同,最高位同时为11

    那么问题就转化成,求yx=yxy-x=y\oplus x(x,y)(x,y)的对数。

    满足yx=yxy-x=y\oplus x,那么yy二进制下为11xx0011yy二进制下为00xx必为00

    考虑数位dpdp,这种类型的数位dpdp不像常规的数位dpdp,用0r0\sim r的答案减去0l10\sim l-1的答案。

    我们考虑枚举哪一位为最高位,然后dp[i][x1][x2]dp[i][x1][x2]表示前ii位,数的大小有没有达到下界LL,有没有达到上界RR的方案数,转移时先枚举yy,再枚举xx

    还有一道类似的题,做法是相同的。

    Code Below:Code\ Below:

    #include<bits/stdc++.h>
    #define ts cout<<"ok"<<endl
    #define int long long
    #define hh puts("")
    #define pc putchar
    #define mo 1000000007
    //#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    //char buf[1<<21],*p1=buf,*p2=buf;
    using namespace std;
    const int N=65;
    int l,r,lenl,lenr,pl[N],pr[N],dp[N][2][2],ans;
    inline int read(){
        int ret=0,ff=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)){ret=ret*10+(ch^48);ch=getchar();}
        return ret*ff;
    }
    void write(int x){if(x<0){x=-x,pc('-');}if(x>9) write(x/10);pc(x%10+48);}
    void writeln(int x){write(x),hh;}
    void writesp(int x){write(x),pc(' ');}
    int dfs(int pos,int x1,int x2){
        if(!pos) return 1;
        if(dp[pos][x1][x2]!=-1) return dp[pos][x1][x2];
        int &res=dp[pos][x1][x2];res=0;
        int t1=x1?pl[pos]:0,t2=x2?pr[pos]:1;
        for(int y=t1;y<=t2;y++)
            for(int x=t1;x<=y;x++)
                res=(res+dfs(pos-1,x1&(x==t1),x2&(y==t2)))%mo;
        return res;
    }
    signed main(){
        memset(dp,-1,sizeof(dp));
        l=read(),r=read();
        while(l){
            pl[++lenl]=l&1;
            l>>=1;
        }
        while(r){
            pr[++lenr]=r&1;
            r>>=1;
        }
        for(int i=lenl;i<=lenr;i++) ans=(ans+dfs(i-1,i==lenl,i==lenr))%mo;//枚举哪个最高位为1 
        write(ans);
        return 0;
    }
    
    • 1

    信息

    ID
    11728
    时间
    2000ms
    内存
    1024MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者