1. 程式人生 > 實用技巧 >【Codeforces Round #643 (Div. 2) C】Count Triangles

【Codeforces Round #643 (Div. 2) C】Count Triangles

題目連結

連結

翻譯

讓你找 \(3\) 條邊 \(x,y,z\), 要求 \(A\le x\le B\le y\le C\le z\le D\)

\(x,y,z\) 能組成三角形。

問你這樣的 \(x,y,z\) 的個數。

題解

對於最後選出來的邊,我們只需要關注 \(x+y\) 是不是大於 \(z\) 就好了 (兩邊之和大於第三邊)。

因為 \(x<=y<=z\)\(x,y,z\) 都是正整數。所以 \(y+z>x\)\(z+x>y\) 恆成立。

首先, 比較明顯的是我們可以先列舉其中一條邊 \(x\)

然後 \(y\) 的話會從 \(B\)\(C\)

變化,那麼 \(x+y\) 就會在 \([x+B,x+C]\) 這個區間內變化。

這個區間和 \([C,D]\) 這個區間的相交情況有 \(5\) 種可能(除去完全在 \([C,D]\) 左邊這種情況不可能)。

分別把這 \(5\) 種情況畫出來, 算一下 \(y\) 在這個區域裡面對答案的貢獻就好了(\(z\) 的值要比 \(x+y\) 來的小)。

會對應很多的類似1,2,3,4... 的公差為 \(1\) 的等差數列(用求和公式算一下答案)。以及整個 \([C,D]\) 區域的值都可以取的情況(x+y>D)。

強烈建議畫個數軸來討論!

程式碼

#include <bits/stdc++.h>
#define LL long long
using namespace std;

LL a,b,c,d;

int main(){
    ios::sync_with_stdio(0),cin.tie(0);
    cin >> a >> b >> c >> d;
    LL ans = 0;
    for (LL x = a;x <= b;x++){
        if (x+b>d){
            ans += (d-c+1)*(c-b+1);
            continue;
        }
        if (x+b <= c && x+c <= d){
            ans += (1+x)*x/2;
        }
        if (x+b <= c && x+c > d){
            ans += (1+d-c)*(d-c)/2+(x+c-d)*(d-c+1);
        }
        if (x+b > c && x+c <= d){
            LL a1 = x+b-c,n = c-b+1;
            LL an = a1 + n - 1;
            ans += (a1+an)*n/2;
        }
        if (x+b > c && x+c > d){
            LL a1 = x + b - c;
            LL n = (d-x-b+1);
            LL an = a1 + n-1;
            ans += (a1+an)*n/2;
            ans += (x+c-d)*(d-c+1);
        }
    }
    cout << ans << endl;
    return 0;
}