【洛谷4193】数字(简单数学题)
- 定义\(S(n)\)为\(n\)各位数字之和并定义\(D(n)=\begin{cases}S(n)&S(n)<10,\\D(S(n))&S(n)\ge10\end{cases}\),求\([l,r]\)中有多少个数可以表示为\(x\times D(x)\)的形式。
- 数据组数\(\le20,l\le r\le 10^{18}\)
数学推导
众所周知,\(S(n)\equiv n(mod\ 9)\),则进一步就可以推得\(D(n)\equiv n(mod\ 9)\)。又因为\(D(n)\in[1,9]\),所以可以直接根据\(n\%9\)来确定出\(D(n)\)的值。
而这种问题的一个套路就是拆分成\([1,l-1]\)和\([1,r]\)两个询问,所以只要考虑求解\([1,n]\)的答案。
因此枚举\(i=D(x)\),则\(x=9k+i\),\(x\times D(x)=9ki+i^2\),所以\(9ki+i^2\le n\)即\(k\le\lfloor\frac{n-i^2}{9i}\rfloor\),那么共有\(\lfloor\frac{n-i^2}{9i}\rfloor+1\)个解。
结束了?
然而并没有,因为一个数可能可以同时表示成多个不同的\(x\times D(x)\)。
那么加设有两个不同的\(D(x)\)分别等于\(i,j\),满足\(9pi+i^2=9qj+j^2\),变形一下有\(pi-qj=\frac{(j+i)(j-i)}9\)。
由于左边的式子是整数,因此\(9|(j+i)(j-i)\),则\(9|(j+i)\)或\(3|(j-i),3|(j+i)\),最后发现只有当\(i+j=9\)的时候才有可能。
因此一个数最多被计算两次,只需考虑有多少个数是被重复计算的即可。
枚举\(i\in [1,4]\),不妨令\(j=9-i\),其实也就是要求\(pi-qj=\frac{(j+i)(j-i)}9\)的自然数解\(p,q\)的对数。
再变个形就得到:\(p=\frac{\frac{(j+i)(j-i)}9+9qj}i\)。那么就是\([0,\lfloor\frac{n-j^2}{9j}\rfloor]\)中满足\(i|(9j\cdot q+\frac{(j+i)(j-i)}9)\)的\(q\)的个数。
反正\(i\)很小,直接枚举\(q'=q\%i\)代入式子中检验,如果可行,就只要求\([0,\lfloor\frac{n-j^2}{9j}\rfloor]\)中满足\(q\% i=q'\)的数的个数,显然是\(\lfloor\frac{\lfloor\frac{n-j^2}{9j}\rfloor-q'}i\rfloor+1\)。
代码:\(O(81T)\)
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define LL long long
using namespace std;
I LL Calc(CI a,CI b,Con LL& n)//计算a,b算重的数的个数
{
RI o=(b*b-a*a)/9;LL m=(n-b*b)/9/b,t=0;//m记录取值上界
for(RI i=0;i^a;++i) !((i*b+o)%a)&&(t+=(m-i+a)/a);return t;//枚举模a的余数计算
}
int main()
{
RI Tt,i;LL l,r,t=0;scanf("%d",&Tt);W(Tt--)
{
for(scanf("%lld%lld",&l,&r),t=0,i=1;i<=9;++i) t+=(r-i*i+9*i)/9/i-(l-1-i*i+9*i)/9/i;//枚举D(x)计算
for(i=1;i<=4;++i) t-=Calc(i,9-i,r)-Calc(i,9-i,l-1);printf("%lld\n",t);//减去算重的方案数
}return 0;
}