Cod sursa(job #3324479)

Utilizator maxtraAlex Deonise maxtra Data 22 noiembrie 2025 11:19:17
Problema Numarare triunghiuri Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 2.23 kb
/*
ai N betisoare, fiecare cu o lungime
vrei sa aflii in cate moduri poti alege 3 betisoare astefl incat ele sa poata forma un triunghi

regula triunghiului:
pentru orice 3 laturi: a + b >= c, unde c este cea mai mare

Obs: pentru problema asta, este permisa chiar si egalitatea, pentru ca sunt valide si cazurile
degenerate unde triunghiul are un unghi de 180

de ce este nevoie sa sortam?
daca pastram betisoarele in ordine crescatoare:
v[i] <= v[j] <= v[k]
atunci singura conditie de verificat este 
v[i] + v[j] >= v[k]
celelalte doua inegalitati sunt automat adevarate pentru ca v[k] este cel mai mare

idee:
pentru fiecare pereche de betisoare (i, j) cautam cate betisoare k > j satisfac:
v[i] + v[j] >= v[k]
asta este exact o cautare binara pe intervalul [j+1...n-1]
rezultatul:
daca cel mai mare k valid este r, atunci avem:
r - j betisoare valide
si le adaugam la rezultat

de ce este corect bs?
v este sortat
conditia v[k] <= suma este un predicat monotomic

complexitate temporala:
sortare: O(nlogn)
bucla: O(n^2)
bs: O(longn)
total: O(n^2logn)
*/
#include <bits/stdc++.h>
#define NMAX 801
using namespace std;

ifstream in("nrtri.in");
ofstream out("nrtri.out");

int main() {
    int n, v[NMAX];
    in >> n;

    // citim lungimile bețișoarelor
    for (int i = 0; i < n; ++i)
        in >> v[i];

    // sortăm ca să putem aplica regula v[i] + v[j] >= v[k]
    sort(v, v + n);

    long long cnt = 0;

    // alegem primul bețișor al tripletului
    for (int i = 0; i < n - 2; ++i)
        // alegem al doilea bețișor
        for (int j = i + 1; j < n - 1; ++j) {
            int s = v[i] + v[j];      // maximul permis pentru v[k]

            // căutăm cu binary search cel mai mare k cu v[k] ≤ s
            int low = j + 1, high = n - 1, r = j;

            while (low <= high) {
                int mid = low + (high - low) / 2;

                if (v[mid] <= s){
                    r = mid;          // mid poate forma triunghi
                    low = mid + 1;    // căutăm mai la dreapta
                }
                else
                    high = mid - 1;   // prea mare, mergem la stânga
            }

            // pentru (i, j) numărul de k valide este (r - j)
            cnt += (r - j);
        }

    out << cnt;
    return 0;
}