1 条题解

  • 0
    @ 2025-8-24 21:32:08

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 阿丑
    ArrTue

    搬运于2025-08-24 21:32:08,当前版本为作者最后更新于2021-05-10 09:42:29,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    传送门

    题目大意:

    • 求小于 10x10^x 并且满足“对其倒序数与其本身求和的结果每位数都是奇数”的数的数量。

    • 3x4003 \le x \le 400

    题目中的例子:n=409n=409,其倒序数 reverse(n)reverse(n) 就是 904904,求和是13131313,每位数都是奇数,满足条件。

    而题目中的首位不能是 00,指的不仅是 nn 不含前导零,还指不能有 n=10n=10 这样的情况,因为 reverse(10)=01reverse(10)=01 含前导零。

    思路:

    1. 通过数学方法推导出公式。

    2. 因为位数 x400x\le 400,暴力高精即可。

    下文将 n+reverse(n)n+reverse(n) 记作 sum(n)sum(n)


    数学部分

    假设 n=af(n)af(n)1...a2a1n=\overline{a_{f(n)}a_{f(n)-1}...a_2a_1},其中 f(n)f(n) 表示 nn 的位数,且有 0a90 \le a \le 9a1a_1af(n)0a_{f(n)} \ne 0

    则 $n+reverse(n)=\overline{a_{f(n)}a_{f(n)-1}...a_2a_1}+\overline{a_1a_2...a_{f(n)-1}a_{f(n)}}$

    $=\sum\limits^{f(n)}_{i=1}(a_i+a_{f(n)-i+1})×10^{i-1}$

    为叙述方便,下列表格表示了 \sum 中的每一项。以 f(n)=7f(n)=7 为例。

    [7] [6] [5] [4] [3] [2] [1]
    a7+a1a_7+a_1 a6+a2a_6+a_2 a5+a3a_5+a_3 a4+a4a_4+a_4 a3+a5a_3+a_5 a2+a6a_2+a_6 a1+a7a_1+a_7

    显然,第 ii 项(ai+af(n)i+1a_i+a_{f(n)-i+1})和第 f(n)i+1f(n)-i+1 项(af(n)i+1+af(n)(f(n)i+1)+1a_{f(n)-i+1}+a_{f(n)-(f(n)-i+1)+1})完全相同;并且 sum(n)sum(n) 的第 ii 位就等于第 ii 项的个位和第 i1i-1 项的十位之和。接下来会借助这两点性质,将 sum(n)sum(n) 的可能情况讨论出来。

    温馨提示:请注意区分 sum(n)sum(n) 的第 ii 位和 [ii](即第 ii 项)之间的区别。

    首先,为使第 1 位(从右往左)为奇数,[1] 中必须为奇数。考虑到进位对其他位的影响,分为两种情况:大于 1010 的奇数与小于 1010 的奇数。

    1、[1] 中是大于 1010 的奇数

    此时,[1](a1+a7a_1+a_7)可以取 1111131315151717,不妨以 1515 为例。

    [7] [6] [5] [4] [3] [2] [1]
    15 15

    这里,[6] 是不能进位的,否则会使 sum(n)sum(n) 的第 7 位成为偶数。而由第 2 位为奇数知,[2] 内一定是偶数(因为 [1] 进位了)而 [2] 与 [6] 相同,故是不进位的偶数,即 0022446688。以 88 为例。

    [7] [6] [5] [4] [3] [2] [1]
    15 8 8 15

    同理,[5] 必须进位,而 [3] 必须是奇数,那么就是进位的奇数,可以发现与 [1]、[7] 符合的条件相同,即产生了循环。那么剩下的过程就可以递归求解。

    但由于 f(n)f(n) 的不同,情况也会不一样;由于四位(左右各两位)一循环,所以有四种情况。

    f(n)%4=0f(n)\%4=0

    f(n)=4f(n)=4 为例。

    [4] [3] [2] [1]
    15 8 15

    此时第 3 位是偶数,不满足题设。

    f(n)%4=1f(n)\% 4=1

    f(n)=5f(n)=5 为例。

    [5] [4] [3] [2] [1]
    15 8 11 8 15

    此时 [3] 是奇数,而 [3]=2a2=2a_2 为偶数,两者冲突。

    f(n)%4=2f(n)\% 4=2

    f(n)=6f(n)=6 为例。

    [6] [5] [4] [3] [2] [1]
    15 8 11 8 15

    此时第 4 位是偶数(11[4]%10+11[3]/10=211_{[4]}\%10+11_{[3]}/10=2),不满足题设。

    f(n)%4=3f(n)\% 4=3

    f(n)=7f(n)=7 为例。

    [7] [6] [5] [4] [3] [2] [1]
    15 8 11 6 11 8 15

    此时是可以满足题设的。(与上表对应的 sum(n)sum(n)1591719515917195

    而通过枚举数学方法得知,[1] 与 [7] 对应的 a1a_1a7a_7 一共有 2020 种情况,[4] 对应的 a4a_455 种情况(请自行推导 orz)。而 [6] 与 [2] 有 2020 种情况,[5] 与 [3] 有 2525 种情况。而在上文推导过,一次“循环”是两位,由乘法原理知一次“循环”是 20×25=50020×25=500 种情况。

    故一共有 20×5×500(f(n)3)/420×5×500^{(f(n)-3)/4} 种情况。注意,一定在 f(n)3(mod4)f(n)\equiv 3(mod 4) 时才成立。

    2、[1] 中是小于 1010 的奇数

    此时,[1] 可以取 1133557799,不妨以 77 为例。

    [7] [6] [5] [4] [3] [2] [1]
    7 7

    [6] 不能进位,否则会使第 7 位成为偶数。而由第 2 位为奇数知,[2] 内一定是奇数。故是不进位的奇数,与 [1]、[7] 符合条件相同。即再次产生了循环。

    当然,f(n)f(n) 不同时情况也不一样。当 f(n)%2=1f(n)\% 2=1 时,最中间一位会是奇数。仍以 f(n)=7f(n)=7 作为例子,即 [4] 为奇数;而 [4]=2a4=2a_4 为偶数,矛盾。

    f(n)%2=0f(n)\% 2=0 时,以 f(n)=4f(n)=4 为例:

    [4] [3] [2] [1]
    5 3 5

    类似地,可以推出 [1] 与 [4] 对应的 a1a_1a4a_42020 种情况,而 [3]、[2] 对应的 a2a_2a3a_32525 种情况,即一“循环”是 2525 种情况。一共有 20×25(f(n)2)/220×25^{(f(n)-2)/2} 种情况。


    高精部分

    由以上的数学推论,可以知道我们只需要写出高精乘低精、高精加高精(统计答案)即可。具体写法可以参考代码部分。


    #include<bits/stdc++.h>
    using namespace std;
    const int N=400+20;
    struct BigInt {
    	int a[N], len;
    	inline void carry() {	//进位,顺便更新 len 
    		for(int i=0; i<len; i++) {
    			a[i+1]+=a[i]/10, a[i]%=10;
    			if(a[len]) ++len;	//更新 len 
    		}
    	}
    	BigInt operator = (int i2) {	//将低精赋值给高精 
    		for(int i=1; i<=N-3; i++) a[i]=0;	//清零 
    		len=1, a[0]=i2, carry();
    	}
    	BigInt operator * (int i2) {	//高精乘低精
    		BigInt ret=*this;
    		for(int i=0; i<ret.len; i++) ret.a[i]*=i2;
    		ret.carry();
    		return ret;
    	}
    	BigInt operator + (BigInt b2) {	//高精加高精
    		BigInt ret=*this;
    		ret.len=max(ret.len, b2.len);
    		for(int i=0; i<ret.len; i++) ret.a[i]+=b2.a[i];
    		ret.carry();
    		return ret;
    	}
    	inline void output() {	//输出
    		for(int i=len-1; i>=0; i--) printf("%d", a[i]);
    	}
    } ans;
    
    int x;
    int main() {
    	ans=0;
    	scanf("%d", &x);
    	for(int i=1; i<=x; i++) {	//从 1 到 x 都要计算
    		if(i%2==0) {	//f(n)%2==0
    			BigInt dl;
    			dl=20;
    			for(int t=1; t<=(i-2)/2; t++) dl=dl*30;	//(i-2)/2 次幂 
    			ans=ans+dl;
    		} else if(i%4==3) {	//f(n)%4==3
    			BigInt dl;
    			dl=20*5;
    			for(int t=1; t<=(i-3)/4; t++) dl=dl*(20*25);	//(i-3)/4 次幂
    			ans=ans+dl;
    		} 
    	}
    	ans.output();
    	return 0;
    }
    
    update 21.6.8:将代码尽量改成了初学者能够接受的写法,并更正了笔误。
    • 1

    信息

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