这题坑了我将近5个小时!!!
题目大意:
有一个无限大的平板
我们定义A[i,j]表示平板上第i行第j列的数字:
1. A[i,1] = i,
2. A[i,j] = A[i,j-1] + Rev( A[i,j-1] ), 其中Rev(x)表示x在10进制下的翻转,例如Rev(213) = 312, Rev(406800) = 008604 = 8604 。
Q个问题,给你两个整数A和B,请问区间[A,B]的数字总共在平板上出现了多少次?
(1 <= A,B <= 10^10
解法
首先我们观察一个6位的数与他的反转的和:
不难发现,除第一位a1无法为0外,ai的取值在0..9之间,且结果的位是对称的,也就是说,ai+aj的取值在0+0~9+9之间,即0~18共19个数,那我们可以很愉快的得出,当x≤10^10时,x+rev(x)约有19^5个结果。
由于时限是5s,我们可以先枚举a1+an,a2+an-1,,,,an+a1这5个数,然后将他们组合、算出所有可能的数在第二列出现的次数,因为平板无限大所以第一列会有所有可能的x。
组合出的数的次数就是这5个数的方案数的乘积,比如2的方案数有[0,2][1,1][0,2]共3个。
然后我们用hash存下非第一列出现的数,将所有数排序,然后对于一个x就去贡献x+rev(x)的方案数,最后做一个前缀和处理询问就可以了。
需要注意的地方
- 要注意a1+an如果是<10的,那么要将a1=0的方案删除!!
- 如果枚举出来的数是奇数位,那么最中间那一位的方案数只有一而且必须要是偶数,因为是两个同样的数相加得到的。
- hash表的key要开素数,假设你开了一个mo=xy,那么要是要hash的数的约数与x或y有关系的话那冲突的概率就会增加,所以key最好是开素数
亲测开素数2000+ms,不开素数5000+ms。