codeforces1355 C. Count Triangles

codeforces1355 C. Count Triangles

		         time limit per test:1 second
		       memory limit per test:256 megabytes
		             input:standard input
					output:standard output

Like any unknown mathematician, Yuri has favourite numbers: A ,B, C, and D, where ABCD. Yuri also likes triangles and once he thought: how many non-degenerate triangles with integer sides x, y, and z exist, such that A ≤ x ≤ B ≤ y ≤ C ≤ z ≤ D holds?

Yuri is preparing problems for a new contest now, so he is very busy. That’s why he asked you to calculate the number of triangles with described property.

The triangle is called non-degenerate if and only if its vertices are not collinear.

Input
The first line contains four integers: A, B, C and D (1≤ABCD≤5⋅105) — Yuri’s favourite numbers.

Output
Print the number of non-degenerate triangles with integer sides x, y, and z such that the inequality A ≤ x ≤ B ≤ y ≤ C ≤ z ≤ D holds.

Examples
input
1 2 3 4
output
4
input
1 2 2 5
output
3
input
500000 500000 500000 500000
output
1
Note

In the first example Yuri can make up triangles with sides (1,3,3), (2,2,3), (2,3,3) and (2,3,4).

In the second example Yuri can make up triangles with sides (1,2,2), (2,2,2) and (2,2,3).

In the third example Yuri can make up only one equilateral triangle with sides equal to 5⋅105.

这个题目我们分开来算,分别求出 x、y、z 可以取到的值的个数然后把三者做乘积,就可求得最终答案。(这个题我个人感觉更加偏向数学型的题目。)

题解

因为
A ≤ x ≤ B , A ≤ x ≤ B, AxB, B ≤ y ≤ C B ≤ y ≤ C ByC
根据上式,我们可以得出 (x + y) 的范围是(令 (x + y)==i))
A + B ≤ i ≤ B + C A + B ≤ i ≤ B + C A+BiB+C
根据三角形的构成规则,两边之和一定要大于第三边,这个三角形才可以成立,也就是说 ( x + y ) 的值必须要比 z 的值要大( z的范围是[ C, D ] ),那么也就可以推导出下式:
C + 1 ≤ i ( i 是 等 于 x + y 的 ) C + 1 ≤ i (i 是等于 x+y 的) C+1iix+y
因为如果 i 的值要比 C + 1 小的话(因为只能取整数),那么 i 最大只能取到C ,而这个时候 z 能取的最小值也是 C ,那么这个时候就变成了:
( x + y ) = = i ≤ C ≤ z ≤ D ( x + y ) == i ≤ C ≤ z ≤ D (x+y)==iCzD
很明显,这样就成了两边之和 ( x + y)小于第三边(z),这样就不能构成一个三角形。这时我们又得出 i 的另外一个限制条件,现在我们有两个 i 的限制条件了,我们大概可以把 i 的范围推一推了。
A + B ≤ i ≤ B + C A + B ≤ i ≤ B + C A+BiB+C C + 1 ≤ i C + 1 ≤ i C+1i
根据这两个不等式我们可以准确的推出 i 的范围
m a x ( A + B , C + 1 ) ≤ i ≤ B + C max( A+B, C + 1) ≤ i ≤ B + C max(A+B,C+1)iB+C
用代码表示就是这样:

for (ll i = max(C+1,A+B); i <= B+C; i++)

只有取 A+B 和 C+1 当中的较大的那个数,才能保证 i 的值是大于 C ( z可以取到的最小值)。
现在我们已经确定了 x+y 的取值范围,那么我们一个个取遍历 x+y 可以取到的值(把 x+y 看成是不变的一个数),每 x+y 取到一个数对应的 z 的值的变化范围也就可以根据 x+y 确定下来。

下面我们来固定一个 x+y 的值,来推导一下这个固定的 x+y 值下对应的 z 可以取到的值的变化范围。我们分两种情况来分析:

  1. x+y 大于 D (此时 x+y 的取值超过 z 的取值范围了),也就是相当于任意的 z 的取值(在 z 的取值范围i内),z 都比 x+y 要小,也就是任意的 z 的取值都可以和 x+y 构成三角形关系,这是 z 的取值范围就是 C ≤ z ≤ D。在这种情况下 z 可以取值的个数为:
    z = D − C + 1 z = D - C + 1 z=DC+1
  2. C+1 ≤ x+y ≤ D,这时候,因为要构成三角形关系,x+y 的值必须要大于 z 的值,这时候 z 的可以取值的范围就缩小到了 [ C, x+y ),即 C ≤ z ≤ x+y == i。这种情况下 z 可以取值的个数为:
    z = i − C ( 因 为 z 不 可 以 取 到 i , 所 以 不 用 加 一 ) 。 z = i - C (因为 z 不可以取到 i ,所以不用加一)。 z=iCzi
    我们已经确定了 z 的取值个数,这时只要剩下在求出 x 或者 y 的在它们的取值范围内可以取值的个数就可以确定总的可以构成的三角形的取值个数(因为 x+y == i,所以 y = i - x) 。
    根据 A ≤ x ≤ B , B ≤ y ≤ C A ≤ x ≤ B, B ≤ y ≤ C AxB,ByC的关系,我们可以知道,当 x 取值取到最大的时候,留给 y 的取值达到最小(因为 y = i - x,我们这里依旧把 i 看成事一个固定的值,只要 y 确定下来了,x 自然就也确定了),这时候 ymin = i - xmax。当 x 取值取到最小的时候,留给 y 取的值达到最大,这时候 ymax = i - xmin y   m i n   = i − x   m a x   = i − B y~min~ = i - x~max~ = i - B y min =ix max =iB y   m a x   = i − x   m i n   = i − A y~max~ = i - x~min~ = i - A y max =ix min =iA
    由于 y 也是有范围限制的 y 最小不能小于 B,所以 ymin = max( B, i - B),y 最大不能大于 C,所以 ymax = min( C, i - A)。这时根据 ymax 和 ymin 我们可以求得 y 的范围是:
    y = y   m a x   − y   m i n   + 1 y = y~max~ - y~min~ + 1 y=y max y min +1
    y = m a x ( B , i − B ) − m i n ( C , i − A ) + 1 y = max( B, i - B) - min( C, i - A)+ 1 y=max(B,iB)min(C,iA)+1
    在这个范围内为 y 可以取的值的个数(这个范围内的 y 的值加上 x 等于 i,因为 y 是在一个范围内变动,而确定 y 之后 x 也就相对应的确定了下来(x = i - y))。
    这时我们就可以列式:
    r e s + = ( y   m a x   − y   m i n   ) ∗ m a x ( i − C , D − C + 1 ) res += (y~max~ - y~min~)*max( i - C,D- C + 1) res+=(y max y min )max(iCDC+1
    这个算式表示,在一个固定的 i 的取值下 y 可以取值的个数乘以 z 可以取值的个数( x 可以由 y 来确定 x = i - y),这时候就等于在这个固定的 i 的取值下可以构成的三角形的个数,最后我们遍历把所有 i 可以取的值都遍历一遍求和就可以得出总的三角形个数了。贴出代码如下:
C++
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll A,B,C,D;
ll x,y,z;
int main()
{
    ll res = 0; 
    scanf("%d %d %d %d",&A,&B,&C,&D);
    for (ll i = max(C+1,A+B); i <= B+C; i++)
    {
        ll ymin = max(i-B,B);
        ll ymax = min(i-A,C);
        res += (ymax - ymin + 1)*min(i-C,D-C+1);
    }
    printf("%lld",res);
    system("pause");
    return 0;
}
python
A, B, C, D = map(int,input().split())
res = 0
for i in range(max(C+1,A+B),B+c+1)
    ymin = max(i - B, B)
    ymax = min(i - A,C)
    res += (ymax - ymin + 1)*min(i-C,D-C+1)
print(res)   # python代码没有提交测试,不知道准确性如何
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值