1 条题解

  • 0
    @ 2026-10-18 18:40:17

    G5018 [GESP202509 五级] 有趣的数字和 题解

    知识点:数位动态规划、二进制、区间求和。

    解题思路

    用二进制数位DP计算前缀[0,N]内二进制1位数为奇数的数字之和。状态记录位号、奇偶性和是否贴上界,并同时返回方案数与数值和,区间答案作前缀差。

    为什么正确

    每一条二进制选择路径唯一对应一个数字,奇偶位累计判定合法性;当前位为1时增加该位权乘后缀方案数,精确累加数值。

    易错点

    不是统计合法数字个数;必须同时返回count与sum;l=0时前缀l-1返回0。

    复杂度

    本题每个前缀O(log N)状态,空间O(log N)。

    参考代码(C++17)

    #include<bits/stdc++.h>
    
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        auto f=[](long long n) {
            if(n<0)return 0LL;
            function<pair<long long,long long>(int,int,bool)>dp;
            map<pair<int,int>,pair<long long,long long>>memo;
            dp=[&](int b,int parity,bool tight)->pair<long long,long long> {
                if(b<0)return  {
                    parity==1,0
                }
                ;
                if(!tight&&memo.count({b,parity}))return memo[ {
                    b,parity
                }
                ];
                long long count=0,sum=0;
                int maxbit=tight?((n>>b)&1):1;
                for(int v=0;v<=maxbit;v++) {
                    auto [c,s]=dp(b-1,parity^v,tight&&v==maxbit);
                    count+=c;
                    sum+=s+c*v*(1LL<<b);
                }
                auto z=make_pair(count,sum);
                if(!tight)memo[ {
                    b,parity
                }
                ]=z;
                return z;
            }
            ;
            return dp(30,0,true).second;
        }
        ;
        long long l,r;
        cin>>l>>r;
        cout<<f(r)-f(l-1);
    }
    

    说明

    本题解为配套教学整理,非官方题解。复杂度按本页参考实现计算,题库使用16个自行生成的测试点。

    • 1

    信息

    ID
    742
    时间
    200ms
    内存
    512MiB
    难度
    普及+
    标签
    递交数
    0
    已通过
    0
    上传者