1 条题解

  • 0
    @ 2025-8-24 21:24:14

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar karma
    **

    搬运于2025-08-24 21:24:13,当前版本为作者最后更新于2017-11-10 09:55:26,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    看完下面的两篇题解,我总觉得有些敷衍.只是给出结论,没有证明.估计怎么证明自己也不清楚.只是打表找规律.

    我来粗略地证明一下:

    证明:

    我们先从简单情况入手,取一个两位数A=10X+Y.X为十位,Y为个位.

    则S(A)乘S(A)=(X+Y)^2 = X^2 + 2XY + Y^2.

    又A*A=(10X+Y)^2 = 100X^2 +20XY + Y^2

    比较两者系数.若A为兔子数,则X^2 不能大于10,否则会进位.

    XY也不能大于10,进位后得到的答案不一样.故可得X<=3 ,Y<=3.

    以此类推,在此就不赘述了.我自己推了一下,三位数也可以通过这个方法推出来X<=3 Y<=3 Z<=3 .故我们猜想兔子数的每一位都小于等于3.

    于是我们可以dfs+如上的剪枝.或者打表+二分.

    又我们发现:如果当前的数不是兔子数,一定是当前最高位的问题.因为之前都可以,当前修改最高位不成了,一定是最高位的锅.于是就不搜了.continue掉.

    代码:

    #include<cstdio>
    int L, R;
    long long S(long long x) {
        int ans = 0;
        while (x > 0)
            ans += x%10, x /= 10;
        return ans;
    }//计算数字的每一位之和 
    int cal(int cur) {
        int ans = 0;
        for (int i=0; i<4; i++) {//定理:兔子数的每一位小于等于3 
            long long x = cur*10 + i;//扩大数字(即添加高位) 
            if (x == 0 || S(x*x) != S(x)*S(x))
                continue;//特判0 :因为题目要求正整数 
                //如果该数不符合要求,那么一定是当前位添加数的问题,即使高位再添加任何数都不行. 
            if (L <= x && x <= R)
                ans ++;//符合条件 
            if (x <= R/10)//还可以继续搜 
                ans += cal(x);
        }
        return ans;
    }
    int main() {
        scanf("%d%d",&L,&R);
        printf("%d",cal(0));//从0开始搜 
        return 0;
    }
    
    • 1

    信息

    ID
    360
    时间
    1000ms
    内存
    125MiB
    难度
    3
    标签
    递交数
    0
    已通过
    0
    上传者