科学家正在计划利用 CSP-2021 行星上的一个研究模块进行一项重要的测量实验,测量共分为两次进行。 因为宇宙中有多种不确定因素,科学家们已经确定了最佳测量的时间在 L 到 R 范围内。 测量的要求是两次测量的间隔时间必须是 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函数不行。