把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷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;
}
posted @ 2021-05-10 19:22  TheLostWeak  阅读(79)  评论(0编辑  收藏  举报