科学家正在计划利用 CSP-2021 行星上的一个研究模块进行一项重要的测量实验,测量共分为两次进行。 因为宇宙中有多种不确定因素,科学家们已经确定了最佳测量的时间在 LR 范围内。 测量的要求是两次测量的间隔时间必须是 A 的倍数,现在请你帮助科学家计算测量方式的数量。 即有多少对测量时间 i 和 j 满足 L <= i < j <= R ,并且 j-i 是 A 的倍数。

示例1

输入:1 5 2 输出:4 说明:1-5之间两数差为2的倍数的组合有(1,3).(1,5),(2,4),(3,5)共4

示例2

输入:4 9 6 输出:0 说明:4-6之间两数差为6的倍数的组合一个都没有所以输出0

步骤一 (求从L到R共有有几个整数)

经测试:任意N个连续整数之间两数差是A的倍数的组合数量是一致的。

所以题目可以理解为求N个连续整数,可以组成两数差为A的倍数的组合有几个?

以示例1为例:L=1,R=5,A=2,得出 N=R-L+1

步骤二 (找规律推导公式)

N=9,A=2为例:连续数字 1,2,3,4,5,6,7,8,9 两数差是A的倍数的组合可分为(A=2)个等差为2的数组

 (1,3,5,7,9)	 共5个等差为2的整数
 (2,4,6,8)		 共4个等差为2的整数

问题1:计算每个等差数组可组两数差为A的倍数的组合有几个

等差数组(1,3,5,7,9),共5个等差为2的整数,所以设数组长度S=5,求两数差为A的倍数的组合有几(Y)个

 (1,3,5,7,9) 		共5个整数等差为2的整数4+3+2+1=10个组合
 (1:3,1:5,1:7,1:9)	4组两数差为2的倍数的组合
 (3:5,3:7,3:9)		3组
 (5:7,5:9)			2组
 (7:9)				1组
 s=5
 y=4+3+2+1=s(s-1)/2=(s*s-s)/2=10

等差数组(2,4,6,8),共4个等差为2的整数,所以设数组长度S=4,求两数差为A的倍数的组合有几(Y)个

 (2,4,6,8) 			共4个整数等差为2的整数3+2+1=6个组合
 (2:4,2:6,2:8)		3组两数差为2的倍数的组合
 (4:6,4:8)			2组
 (6:8)				1组
 s=4
 y=3+2+1=s(s-1)/2=(s*s-s)/2=6

由此得到:Y=(S*S-S)/2

问题2:如何获取每个等差数组的长度,以及同样长度的等差数组有几个?

N=9,A=2,S=intval(N/A),P=N%A,连续数字 1,2,3,4,5,6,7,8,9为例得到:

 (1,3,5,7,9)			长度:5=S+1;	数量:1=P
 (2,4,6,8)				长度:4=S;		数量:1=A-P

N=9,A=3,S=intval(N/A),P=N%A,连续数字 1,2,3,4,5,6,7,8,9为例得到:

 (1,4,7)				
 (2,5,8)
 (3,6,9)				长度:3=S;		数量:3=A-P

P=N%A=0所以没有长度=S+1的等差数组

N=9,A=4,S=intval(N/A),P=N%A,连续数字 1,2,3,4,5,6,7,8,9为例得到:

 (1,5,9)				长度:3=S+1;	数量:1=P
 (2,6)					长度:2=S;		数量:3=A-P
 (3,7)
 (4,8)				

结合问题得到的 Y=(S*S-S)/2 可得到以下公式

 X =(S*S-S)/2*(A-P)+((S+1)*(S+1)-(S+1))/2*P;
 X =(S*S-S)/2*(A-P)+((S*S+S+S+1)-(S+1))/2*P;
 X =(S*S-S)/2*(A-P)+(S*S+S+S+1-S-1)/2*P;
 X =(S*S-S)/2*(A-P)+(S*S+S)/2*P;
 X =((S*S-S)*(A-P)+(S*S+S)*P)/2;
 X =(S*S*(A-P)-S*(A-P)+S*S*P+S*P)/2;
 X =(S*S*A-S*S*P-S*A+S*P+S*S*P+S*P)/2;
 X =(S*S*A-S*A+2*S*P)/2;
 X =(S*S*A-S*A+2*S*P)/2;
 X =S*(S*A-A+2*P)/2;

最终得到 S*(SA-A+2P)/2

实现代码

<?php
$l = trim(fgets(STDIN));
$r = trim(fgets(STDIN));
$a = trim(fgets(STDIN));
$n = $r - $l + 1;
$s = intval($n / $a); //不能使用floor()函数向下取整 不然会出错
$p = $n % $a;
echo ($s * ($s * $a - $a + 2 * $p) >> 1), PHP_EOL; 

floor() 函数

floor() 函数向下舍入为最接近的整数。

语法:floor(x)

返回不大于 x 的下一个整数,将 x 的小数部分舍去取整。floor() 返回的类型仍然是 float,因为 float 值的范围通常比 integer 要大。

intval()函数

intval() 函数用于获取变量的整数值。

intval() 函数可通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。 intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1。

区别:

1、intval()函数是直接舍去小数部分来取整;而floor()函数在参数大于1时,舍去小数部分来取整,当参数小于1时,会舍去小数部分,并在整数的基础上加1。

2、intval()函数可进行进制转换,floor函数不行。