- 定义(S(n))为(n)各位数字之和并定义(D(n)=egin{cases}S(n)&S(n)<10,\D(S(n))&S(n)ge10end{cases}),求([l,r])中有多少个数可以表示为(x imes D(x))的形式。
- 数据组数(le20,lle rle 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 imes D(x)=9ki+i^2),所以(9ki+i^2le n)即(klelfloorfrac{n-i^2}{9i} floor),那么共有(lfloorfrac{n-i^2}{9i} floor+1)个解。
结束了?
然而并没有,因为一个数可能可以同时表示成多个不同的(x imes 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)的时候才有可能。
因此一个数最多被计算两次,只需考虑有多少个数是被重复计算的即可。
枚举(iin [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,lfloorfrac{n-j^2}{9j} floor])中满足(i|(9jcdot q+frac{(j+i)(j-i)}9))的(q)的个数。
反正(i)很小,直接枚举(q'=q\%i)代入式子中检验,如果可行,就只要求([0,lfloorfrac{n-j^2}{9j} floor])中满足(q\% i=q')的数的个数,显然是(lfloorfrac{lfloorfrac{n-j^2}{9j} floor-q'}i floor+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
",t);//减去算重的方案数
}return 0;
}