#include
#include
#include
#include
using namespace std;
ifstream fin(“elevi.in”);
ofstream fout(“elevi.out”);
struct nod{
struct {;
char nume256;
char clasa4;
double medie;
}inf;
nod *urm;
}*p, *u;
void addFront(char nume[], char clasa[], double medie, nod *&p, nod *&u){
if(!p){
p = new nod;
strcpy((*p).inf.nume, nume);
strcpy((*p).inf.clasa, clasa);
(*p).inf.medie = medie;
(*p).urm = NULL;
u = p;
}
else{
nod *q = new nod;
strcpy((*q).inf.nume, nume);
strcpy((*q).inf.clasa, clasa);
(*q).inf.medie = medie;
(*q).urm = NULL;
(*u).urm = q;
u = q;
}
}
void read(int &n){ fin >> n; fin.get(); while(n—){ char nume50; fin >> nume; fin.get();
char clasa10; fin >> clasa; fin.get(); double medie; fin >> medie; fin.get(); addFront(nume, clasa, medie, p, u); } }void cerinta1(){
int k = 0;
for(nod *i = p; i; i = (*i).urm)
if((*i).inf.medie >= 9)k++;
fout << k;
}
void sterge(nod *&i){
if(p == i){
nod *aux = p;
p = (*p).urm;
delete aux;
}
else{
nod *aux = i->urm;
i->urm = i->urm->urm;
delete aux;
}
}
void cerinta2(){
for(nod *i = p; i && i->urm; i = (*i).urm)
if((double)(*(*i).urm).inf.medie < 5)
sterge(i);
if((*p).inf.medie < 5)
sterge(p);
}
void cerinta3(){
for(nod *i=p; i; i=(*i).urm)
fout << (*i).inf.nume << “ “ << (*i).inf.clasa << “ “ << (*i).inf.medie << “\n”;
}
void schimba(nod *&i, nod *&j){
swap(i->inf.medie, j->inf.medie);
swap(i->inf.clasa, j->inf.clasa);
swap(i->inf.nume, j->inf.nume);
}
void sortareList_lexicografic(nod *&p, nod*&u){ for(nod *i = p; (*i).urm; i = (*i).urm) for(nod *j = i->urm; j; j = (*j).urm){ char clasa14, clasa24; strcpy(clasa1, (*i).inf.clasa); strcpy(clasa2, (*j).inf.clasa);
if(strcmp(clasa1, clasa2) > 0) schimba(i, j); else if(strcmp(clasa1, clasa2) == 0 && strcmp(i->inf.medie, j->inf.medie) < 0){ swap(i->inf.medie, j->inf.medie); swap(i->inf.nume, j->inf.nume); } }}
void cerinta4(){
sortareList_lexicografic(p, u);
}
void display(){
for(nod *i=p; i; i=(*i).urm) fout << (*i).inf.nume << “ “ << (*i).inf.clasa << “ “ << (*i).inf.medie << “\n”; }int main()
{
int n;
read(n);
display();
Hey guys, did you know that in terms of male human and female Pokémon breeding, Vaporeon is the most compatible Pokémon for humans? Not only are they in the field egg group, which is mostly comprised of mammals, Vaporeon are an average of 3”03’ tall and 63.9 pounds, this means they’re large enough to be able handle human dicks, and with their impressive Base Stats for HP and access to Acid Armor, you can be rough with one. Due to their mostly water based biology, there’s no doubt in my mind that an aroused Vaporeon would be incredibly wet, so wet that you could easily have sex with one for hours without getting sore. They can also learn the moves Attract, Baby-Doll Eyes, Captivate, Charm, and Tail Whip, along with not having fur to hide nipples, so it’d be incredibly easy for one to get you in the mood. With their abilities Water Absorb and Hydration, they can easily recover from fatigue with enough water. No other Pokémon comes close to this level of compatibility. Also, fun fact, if you pull out enough, you can make your Vaporeon turn white. Vaporeon is literally built for human dick. Ungodly defense stat+high HP pool+Acid Armor means it can take cock all day, all shapes and sizes and still come for more.
imi plac copiii mici ℂℂℂℂℂℂ∅∅∅∅∅∅∅PPPPPPPP∤∤∤∤∤∤∤∤∤∤∤∤∤∤∤∤∤∤∤∤∤ ❤❤💔💔💔❣❣❣💕💖🖤💚💦💦💦💦💦💦💦✡✡✡✡🔯🔯✡🕎
Articolul de față prezintă două rezolvări alternative ale problemei \(\texttt{PrimeIntreEle1}\), de complexități \(\mathcal{O}(n \log n)\), una bazată pe formula de inversiune Möbius, iar cealaltă utilizând indicatorul lui Euler și proprietățile acestei funcții.
Să considerăm problema #PrimeIntreEle1 :
Se citește un număr natural \(n\), \(n > 1\). Să se determine câte perechi \((a, b)\), \(1 \leqslant a \leqslant b \leqslant n\) de numere naturale sunt prime între ele.
O primă soluție constă în numărarea efectivă a perechilor \((a, b)\) cu \(1 \leqslant a \leqslant b \leqslant n\) de numere naturale prime între ele. Această abordare are complexitatea \(\mathcal{O}(n^2 \log n)\), deoarece calculul celui mai mare divizor comun \(\mathrm{cmmdc}(a, b)\) necesită \(\mathcal{O}(\log n)\) pași (complexitatea algoritmului lui Euclid – pentru descrierea acestui algoritm, vezi [5]). Putem descrie cu ajutorul pseudocodului această idee:
───────────────────────────────
Soluție brute-force (\(\mathcal{O}(n^2 \log n)\)).
───────────────────────────────
\(cnt \gets 0\);
\(\texttt{pentru}\;\;a = \overline{1, n}\;\texttt{ execută}\)
│ \(\texttt{pentru}\;\;b = \overline{a, n}\;\texttt{execută}\)
│ │ \(\texttt{dacă}\;\;\text{cmmdc}(a, b) = 1\;\texttt{atunci}\)
│ │ │ \(cnt \gets cnt + 1\);
│ │ └■
│ └■
└■
\(\texttt{scrie } cnt\);
───────────────────────────────
Implementare:
#include <iostream>
using namespace std;
int Cmmdc(int x, int y)
{
int r;
while(y != 0)
{
r = x % y;
x = y;
y = r;
}
return x;
}
int NumarPerechi(int n)
{
int res = 0;
for(int a = 1; a <= n; a++)
for(int b = a; b <= n; b++)
if(Cmmdc(a, b) == 1)
res++;
return res;
}
int main()
{
int n;
cin >> n;
cout << NumarPerechi(n);
return 0;
}
Vom prezenta acum și o altă soluție, mult mai eficientă, bazată pe formula de inversiune a lui Möbius.
Fie \(N = |\{(a, b) \; | \; a, b \in \{1, 2, \ldots, n\}, \text{cmmdc}(a, b) = 1\}|\).
Răspunsul problemei va fi atunci \(\frac{N + 1}{2}\). Într-adevăr, perechea \((a, b)\) cu \(a < b\) va fi numărată de două ori: \((a, b)\) și \((b, a)\), excepție făcând perechea \((1, 1)\) (perechile \((a, a)\) nu vor fi numărate pentru \(a > 1\)).
Funcția Möbius, \(\mu : \mathbb{N}^{\star} \to \mathbb{Z}\) este definită astfel:
\[
\mu(n) =
\begin{cases}
1, \text{ dacă } n = 1 \\
0, \text{ dacă există un număr prim } p \text{ astfel încât } p^2 | n \\
(-1)^k, \text{ dacă } n = p_1 \cdot \ldots \cdot p_k, \text{ unde } p_1, \ldots, p_k \text{ sunt prime distincte}
\end{cases}
\]
De asemenea, definim și funcția unitate \(\varepsilon : \mathbb{N}^{\star} \to \mathbb{N}\),
\[
\varepsilon(n) =
\begin{cases}
1, \text{ dacă } n = 1 \\
0, \text{ altfel }
\end{cases}
\]
Definiție. O funcție \(f : \mathbb{N}^{\star} \to \mathbb{C}\) se numește funcție aritmetică.
Dacă \(f\), \(g\) sunt două funcții aritmetice, atunci \[ f(n) = \sum_{d | n} \mu(d) g\left(\frac{n}{d}\right) \Leftrightarrow g(n) = \sum_{d | n} f(d). \]
Pentru demonstrație, se poate consulta [2].
În particular, luând \(f = \mu\), avem \(\mu(n) = f(n) = \sum_{d | n} \mu(d) \varepsilon\left(\frac{n}{d}\right)\), deci \(g = \varepsilon\), i.e.
\begin{equation}
\sum_{d | n} \mu(d) = \varepsilon(n). \;\;\;\; (1)
\label{eq1}
\end{equation}
Revenind la problemă, avem:
\begin{align*}
N &= |\{(a, b) \; | \; a, b \in \{1, 2, \ldots, n\}, \text{cmmdc}(a, b) = 1\}| \\
&= \sum_{1 \leqslant a, b \leqslant n} \varepsilon(\text{cmmdc}(a, b)) \\
&= \sum_{1 \leqslant a \leqslant n} \sum_{1 \leqslant b \leqslant n} \varepsilon(\text{cmmdc}(a, b)).
\end{align*}
Punând \(n \to \text{cmmdc}(a, b)\) în relația \((1)\), obținem:
\begin{align*}
N &= \sum_{1 \leqslant a \leqslant n} \sum_{1 \leqslant b \leqslant n} \varepsilon(\text{cmmdc}(a, b)) \\
&= \sum_{1 \leqslant a \leqslant n} \sum_{1 \leqslant b \leqslant n} \sum_{d | \text{cmmdc}(a, b)} \mu(d)
\end{align*}
Folosim acum o proprietate cunoscută, anume că \(d | \text{cmmdc}(a, b)\) dacă și numai dacă \(d | a\) și \(d | b\). Deducem că:
\begin{align*}
N &= \sum_{1 \leqslant a \leqslant n} \sum_{1 \leqslant b \leqslant n} \sum_{\substack{d | a \\ d | b}} \mu(d)
\end{align*}
Schimbând ordinea de sumare,
\begin{align*}
N &= \sum_{1 \leqslant a \leqslant n} \sum_{1 \leqslant b \leqslant n} \sum_{\substack{d | a \\ d | b}} \mu(d) \\
&= \sum_{d = 1}^n \mu(d) \sum_{\substack{1 \leqslant a \leqslant n \\ d | a}} \sum_{\substack{1 \leqslant b \leqslant n \\ d | b}} 1 \\
&= \sum_{d = 1}^n \mu(d) \left(\sum_{\substack{1 \leqslant a \leqslant n \\ d | a}} 1\right)^2 \\
&= \sum_{d = 1}^n \mu(d) \left\lfloor\frac{n}{d}\right\rfloor^2.
\end{align*}
Acest lucru este posibil deoarece:
\[\{(a, b, d) | 1 \leqslant a \leqslant n, 1 \leqslant b \leqslant n, d | a, d | b\} = \{(a, b, d) | 1 \leqslant d \leqslant n, 1 \leqslant a \leqslant n, d | a, 1 \leqslant b \leqslant n, d | b\}.\]
De remarcat că am folosit că \[|\{a \;|\; 1 \leqslant a \leqslant n, d | a\}| = |\{k \cdot d \;|\; 1 \leqslant k \cdot d \leqslant n\}| = \left\lfloor\frac{n}{d}\right\rfloor\] pentru un număr \(d \in \{1, 2, \ldots, n\}\) fixat.
În consecință, numărul căutat este
\begin{equation}
N = \sum_{d = 1}^n \mu(d) \left\lfloor\frac{n}{d}\right\rfloor^2. \;\;\;\; (2)
\label{eq2}
\end{equation}
Ecuația \((2)\) ne oferă un mod de calcul pentru \(N\) în \(\mathcal{O}(n)\). În funcție de cum se precalculează funcția \(\mu\), complexitatea variază de la \(\mathcal{O}(n)\) până la \(\mathcal{O}(n \log n)\).
O variantă de calcul a funcției Möbius în timp \(\mathcal{O}(n \log n)\) se bazează pe faptul că \(\mu(1) = 1\) și pe relația \((1)\), ce poate fi rescrisă
\begin{equation}
\mu(n) = \varepsilon(n)\; – \sum_{\substack{d | n \\ d < n}} \mu(d).
\label{eq3}
\end{equation}
Astfel, obținem următoarea schemă pentru calculul funcției \(\mu\):
───────────────────────────────
Precalcularea funcției Möbius \(\mu\)
───────────────────────────────
\(\texttt{mobius}(1) \gets 1\);
\(\texttt{pentru}\;\;i = \overline{1, n}\;\texttt{execută}\)
│ \(\texttt{pentru}\;\;j = \overline{2i, n, i}\;\texttt{execută}\)
│ │ \(\texttt{mobius}(j) \gets \texttt{mobius}(j)\; – \;\texttt{mobius}(i)\);
│ └■
└■
───────────────────────────────
Pentru exemplificare, să luăm cazul \(n = 6\). Avem \(12\) perechi de numere prime între ele: \((1, 1), (1, 2), \ldots, (1, 6), (2, 3), (2, 5), (3, 4), (3, 5), (4, 5), (5, 6)\).
Într-adevăr, aplicând formula de mai sus,
\begin{align*}
N &= \sum_{d = 1}^{6} \mu(d) \cdot \left\lfloor\frac{6}{d}\right\rfloor^2 \\
&= \mu(1) \cdot \left\lfloor\frac{6}{1}\right\rfloor^2 + \mu(2) \cdot \left\lfloor\frac{6}{2}\right\rfloor^2 + \mu(3) \cdot \left\lfloor\frac{6}{3}\right\rfloor^2 + \mu(4) \cdot \left\lfloor\frac{6}{4}\right\rfloor^2 + \mu(5) \cdot \left\lfloor\frac{6}{5}\right\rfloor^2 + \mu(6) \cdot \left\lfloor\frac{6}{6}\right\rfloor^2 \\
&= 36 – 9 – 4 – 1 + 1 \\
&= 23,
\end{align*}
iar răspunsul este dat de \(\frac{N + 1}{2} = \frac{23 + 1}{2} = 12\). (Avem \(\mu(1) = \mu(6) = 1\), \(\mu(2) = \mu(3) = \mu(5) = -1\), \(\mu(4) = \mu(2^2) = 0\).)
Implementare:
#include <iostream>
using namespace std;
const int NMAX = 1000;
int mobius[NMAX + 1];
void Precalc()
{
mobius[1] = 1;
for(int i = 1; i <= NMAX; i++)
for(int j = i << 1; j <= NMAX; j += i)
mobius[j] -= mobius[i];
}
int NumarPerechi(int n)
{
int res = 0;
for(int d = 1; d <= n; d++)
res += mobius[d] * (n / d) * (n / d);
return (res + 1) >> 1;
}
int main()
{
Precalc();
int n;
cin >> n;
cout << NumarPerechi(n);
return 0;
}
Pentru această problemă, mai există încă o soluție în care intervine indicatorul lui Euler. Pentru a calcula \(N := |\{ (a, b) | 1 \leqslant a \leqslant b \leqslant n, \text{cmmdc}(a, b) = 1 \}|\), putem fixa valoarea \(b \in \{1, 2, \ldots n\}\). Atunci:
\[ N = \sum_{b = 1}^{n} |\{ (a, b) | 1 \leqslant a \leqslant b, \text{cmmdc}(a, b) = 1\}|. \]
Fie \(\varphi : \mathbb{N}^{\star} \to \mathbb{N}^{\star}\), \(\varphi(n) = |\{x | 1 \leqslant x \leqslant n, \text{cmmdc}(x, n) = 1\}|\). Cu alte cuvinte, \(\varphi(n)\) reprezintă numărul de numere prime cu \(n\), mai mici sau egale cu \(n\). (Avem \(\varphi(1) = 1\).) Deducem că:
\[ N = \sum_{x = 1}^n \varphi(x) \]
Pentru precalcularea indicatorului lui Euler, vom folosi o proprietate datorată lui Gauss:
\[ \sum_{d | n} \varphi(d) = n \Leftrightarrow \varphi(n) = n \;-\; \sum_{\substack{d | n \\ d < n}} \varphi(d). \]
───────────────────────────────
Precalcularea funcției \(\varphi\)
───────────────────────────────
\(\texttt{phi}(1) \gets 1\);
\(\texttt{pentru } i = \overline{2, n} \texttt{ execută }\)
│ \(\texttt{phi}(i) \gets i \;-\; 1\);
└■
\(\texttt{pentru } i = \overline{2, n} \texttt{ execută } \)
│ \(\texttt{pentru } j = \overline{2i, n, i} \texttt{ execută }\)
│ │ \(\texttt{phi}(j) \gets \texttt{phi}(j) \;-\; \texttt{phi}(i)\);
│ └■
└■
───────────────────────────────
Complexitatea este tot \(\mathcal{O}(n \log n)\).
Remarcă: Pentru precalcularea funcțiilor \(\mu\) și \(\varphi\), complexitatea este \(\mathcal{O}(n \log n)\), deoarece, pentru \(i \in \{2, 3, \ldots, n\}\), \(j\) poate lua cel mult \(\frac{n}{i}\) valori. În total, vor fi efectuate maxim \(\displaystyle{\sum_{k = 1}^n} \frac{n}{k} = n \cdot H_n\) operații, unde \(H_n = \displaystyle{\sum_{k = 1}^n \frac{1}{k}}\).
Observație. Avem \(H_n = \Theta(\log n)\).
Demonstrație. Vom arăta că are loc următoarea inegalitate: \[\frac{n}{2} + 1 \leqslant H_{2^n} < n + 1, \text{pentru orice } n \in \mathbb{N^{\star}}.\]
Într-adevăr, să observăm că: \[\{1, 2, \ldots, 2^n\} = [1, 2^n] \cap \mathbb{N^{\star}} = \{1\} \cup \bigcup_{k = 1}^n \{2^{k – 1} + 1, \ldots, 2^k\}.\]
De aici rezultă \[H_{2^n} = 1 + \sum_{k = 1}^n \sum_{2^{k – 1} < j \leqslant 2^k} \frac{1}{j}.\]
Dar \(2^{k – 1} < j \leqslant 2^k \Leftrightarrow \frac{1}{2^k} \leqslant \frac{1}{j} < \frac{1}{2^{k – 1}}\) și, prin urmare,
\[\frac{1}{2} = \sum_{2^{k – 1} < j \leqslant 2^k} \frac{1}{2^k} \leqslant \sum_{2^{k – 1} < j \leqslant 2^k} \frac{1}{j} < \sum_{2^{k – 1} < j \leqslant 2^k} \frac{1}{2^{k – 1}} = 1.\]
În consecință, \[\frac{n}{2} = \sum_{k = 1}^n \frac{1}{2} \leqslant \sum_{k = 1}^n \sum_{2^{k – 1} < j \leqslant 2^k} \frac{1}{j} < \sum_{k = 1}^n 1 = n,\]
adică \(\frac{n}{2} + 1 \leqslant H_{2^n} < n + 1\), pentru orice \(n \in \mathbb{N^{\star}}\).
Totodată,
\begin{align*}
H_n &= \sum_{k = 1}^n \frac{1}{k} \\
&= \sum_{k = 1}^{n – 1} \frac{1}{k} + \frac{1}{n} \\
&= H_{n – 1} + \frac{1}{n}
\end{align*}
Din această egalitate reiese că \(H_n > H_{n – 1}\), pentru orice \(n \geqslant 2\), adică șirul \((H_n)_{n \geqslant 1}\) este monoton strict crescător.
Fie acum un număr natural \(n \in \mathbb{N^{\star}}\) arbitrar, fixat. Notăm \(k := \lfloor \log_2 n \rfloor\), deci \(k \leqslant \log_2 n < k + 1 \Leftrightarrow 2^k \leqslant n < 2^{k + 1}\).
Din monotonia șirului \((H_n)_{n \geqslant 1}\), obținem \(H_{2^k} \leqslant H_n < H_{2^{k + 1}}\). Conform inegalității precedente, deducem că \(H_{2^k} \geqslant \frac{k}{2} + 1\) și \(H_{2^{k + 1}} < k + 2\), deci \(\frac{k}{2} + 1 \leqslant H_n < k + 2\), i.e. \(H_n = \Theta(\log n)\).
Implementare:
#include <iostream>
using namespace std;
const int NMAX = 1000;
int phi[NMAX + 1];
void Precalc()
{
phi[1] = 1;
for(int i = 2; i <= NMAX; i++)
phi[i] = i - 1;
for(int i = 2; i <= NMAX; i++)
for(int j = i << 1; j <= NMAX; j += i)
phi[j] -= phi[i];
}
int NumarPerechi(int n)
{
int res = 0;
for(int i = 1; i <= n; i++)
res += phi[i];
return res;
}
int main()
{
Precalc();
int n;
cin >> n;
cout << NumarPerechi(n);
return 0;
}
[1] Math note — Möbius inversion
[2] Titu Andreescu, Dorin Andrica, NUMBER THEORY – Structures, Examples, and Problems
[3] Eratostene și alte ciururi
[4] Secvențe Farey
[5] CMMDC și CMMMC. Algoritmul lui Euclid
Se considera urmatoarea cerinta: avem un tablou unidimensional cu n elemente, asupra acestuia se fac doua tipuri de operatii:
1.Update(x, y), elementul de la pozitia x primeste valoarea y.
2.Suma[ST, DR], adica suma elementelor din a cu indicele i, ST≤i≤DR
Prima metoda, elementara, poate solutiona fiecare query de tip suma in O(n) timp si update in O(1) timp, parcurgand efectiv elementele din intervalul dat de query-ul SUMA.
O a doua metoda se bazeaza pe algoritmul de Square Root Decomposition (cunoscut si ca Smenul lui Batog, atat Infoarena, cat si GeeksForGeeks au articole ce explica rationamentul si implementarea). Astfel, complexitatea de timp scade la O(sqrt(n)).
Cea mai eficienta metoda este metoda prin care construim o structura de date arborescenta ce ne garanteaza ca orice operatie de tip update sau suma poate fi executata in O(log n). Modul in care construim acest arbore este urmatorul: la radacina avem intervalul [1, n], descendentii acestuia vor fi [1,n/2] si [n/2+1, n]. Vom mentine aceasta maniera recursiva pana cand ajungem la elemente individuale ale array-ului. Dupa construirea arborelui, trecem la operatia de update. Ideea este ca nu dorim sa actualizam toate nodurile, ci doar parintii nodurilor pana cand ajungem la radacina, astfel operatia va fi logaritmica. Pentru suma ideea este similara: noi impartim recursiv intervalul de cautare in jumatati pana cand gasim un nod ce contine intervalul cautat.
In concluzie, arborii de intervale sunt structuri de date arborescente ce permit rezolvarea eficienta a problemelor unde exista update-uri si query-uri pe intervale. Acestia pot fi implementati intr-o multitudine de probleme din concursuri.
Mai jos va las si implementarea mea a arborilor de intervale:
#include <bits/stdc++.h>
using namespace std;
int v[100], a[401];
void build (int st, int dr, int node) {
if (st == dr) {
a[node] = v[st];
}
else {
int mij = (st + dr) / 2;
build (st, mij, node * 2);
build (mij + 1, dr, node * 2 + 1);
a[node] = a[ node * 2 ] + a[ node * 2 + 1 ];
}
}
void update (int st, int dr, int node, int pos, int val) {
if (st == dr) {
a[node] = val;
v[pos] = val;
}
else {
int mij = (st + dr) / 2;
if (pos <= mij) {
update (st, mij, node * 2, pos, val);
}
else {
update (mij + 1, dr, node * 2 + 1, pos, val);
}
a[node] = a[node * 2 + 1] + a[node * 2];
}
}
int sum (int st, int dr, int node, int target_st, int target_dr) {
if (st>target_dr or dr<target_st) {
return 0;
}
else {
if (target_st <= st and dr <= target_dr) {
return a[node];
}
int mij = (st + dr) / 2;
return sum (st, mij, node * 2, target_st, target_dr) + sum (mij + 1, dr, node * 2 + 1, target_st, target_dr);
}
}
Sper ca v-am ajutat!
Vom prezenta o soluție alternativă a problemei xOy, însă mai ineficientă din punct de vedere al timpului de execuție (de complexitate \(\mathcal{O}(\texttt{VMAX})\), unde \(\texttt{VMAX} = 10^6\)).
În problema #xOy , se cere determinarea poziției unui punct \(P\) de coordonate întregi, fiind date punctele \(A\), \(B\), \(C\) (de coordonate întregi) și distanțele \(PA^2\), \(PB^2\), \(PC^2\) (exprimate tot prin numere întregi).

În rezolvarea problemei, vom folosi următoarea proprietate clasică:
În triunghiul \(\Delta{}ABC\), cu centrul de greutate în \(G\), pentru orice punct \(P \in \mathcal{P}\) din plan are loc egalitatea:
\[ PG^2 = \frac{1}{3}\left(PA^2 + PB^2 + PC^2\right) – \frac{1}{9}\left(AB^2 + BC^2 + CA^2\right). \]
Demonstrație: Deoarece \(G\) este centrul de greutate al \(\Delta{}ABC\), pentru orice punct \(P \in \mathcal{P}\):
\[ \overrightarrow{PG} = \frac{\overrightarrow{PA} + \overrightarrow{PB} + \overrightarrow{PC}}{3}. \]
Prin ridicare la pătrat, vom avea
\begin{align*}
PG^2 = \overrightarrow{PG} \cdot \overrightarrow{PG} &= \frac{1}{9} (\overrightarrow{PA} + \overrightarrow{PB} + \overrightarrow{PC})^2 \\
&= \frac{1}{9} \left(\sum PA^2 + 2 \sum \overrightarrow{PA} \cdot \overrightarrow{PB}\right) \\
&= \frac{1}{9} \left(\sum PA^2 + \sum(PA^2 + PB^2 – AB^2)\right) \\
&= \frac{1}{3} (PA^2 + PB^2 + PC^2) – \frac{1}{9} (AB^2 + BC^2 + CA^2),
\end{align*}
ceea ce încheie demonstrația.
Deoarece distanțele \(PA^2\), \(PB^2\), \(PC^2\) sunt date, iar
\[PG^2 = \frac{1}{3}\left(PA^2 + PB^2 + PC^2\right) – \frac{1}{9}\left(AB^2 + BC^2 + CA^2\right),\]
deducem că \(PG^2 = \text{const} \Leftrightarrow PG = \text{const}\). Așadar, din punct de vedere geometric, \(P\) se află pe un cerc \(\mathcal{C}\) de centru \(G\) și rază \(\sqrt{k}\), unde am notat
\[k := PG^2 = \frac{1}{3}\left(PA^2 + PB^2 + PC^2\right) – \frac{1}{9}\left(AB^2 + BC^2 + CA^2\right).\]

Ne folosi acum de restricțiile problemei, anume că toate cele trei distanțe date și punctele \(A\), \(B\), \(C\) au coordonate întregi. Astfel, numărul
\[k’ := 9k = 3(PA^2 + PB^2 + PC^2) – (AB^2 + BC^2 + CA^2) \in \mathbb{N}.\]
De asemenea, centrul de greutate al triunghiului \(\Delta{}ABC\) are coordonatele:
\begin{cases}
x_G = \dfrac{x_A + x_B + x_C}{3} \in \mathbb{Q}, \\
y_G = \dfrac{y_A + y_B + y_C}{3} \in \mathbb{Q}.
\end{cases}
Apoi \[PG^2 = k \Leftrightarrow (x_P – x_G)^2 + (y_P – y_G)^2 = k \Leftrightarrow (3x_P – x_{G’})^2 + (3y_P – y_{G’})^2 = k’^2,\]
unde am efectuat notațiile:
\begin{cases}
x_{G’} := 3x_G = x_A + x_B + x_C \in \mathbb{Z}, \\
y_{G’} := 3y_G = y_A + y_B + y_C \in \mathbb{Z}.
\end{cases}
Totodată, luând \(x := 3x_P – x_{G’}\) și \(y := 3y_P – y_{G’}\), avem \(x^2 + y^2 = k’\), cu \(x\), \(y\), \(k’ \in \mathbb{Z}\).
Vom determina o soluție \((x, y) \in \mathbb{Z} \times \mathbb{Z}\) a ecuației \(x^2 + y^2 = k’^2\). Revenind la notațiile efectuate,
\begin{cases}
x_P = \dfrac{x + x_{G’}}{3} \in \mathbb{Z}, \\
y_P = \dfrac{y + y_{G’}}{3} \in \mathbb{Z}.
\end{cases}
Am determinat așadar un posibil punct laticial \(P(x_P, y_P) \in \mathcal{C}\), însă trebuie să mai verificăm dacă distanțele de la \(P\) la punctele \(A\), \(B\) și \(C\) sunt cele date în problemă:
\[PA^2 = D_{PA}^2, PB^2 = D_{PB}^2, PC^2 = D_{PC}^2.\]
Să observăm că este necesar ca \(x + x_{G’} \equiv 0 (\text{mod } 3)\) și \(y + y_{G’} \equiv 0 (\text{mod } 3)\).
Vom folosi o structură Point, prin care vom memora coordonatele unui punct:
struct Point
{
int x, y;
};
Pentru două puncte \(p(p_x, p_y)\) și \(q(q_x, q_y)\), definim o funcție Dist(p, q) care să calculeze pătratul distanței dintre acestea, dată de formula:
\[(p_x – q_x)^2 + (p_y – q_y)^2 = dx^2 + dy^2,\]
unde: \begin{cases}
\displaystyle{dx = p_x – q_x}, \\
\displaystyle{dy = p_y – q_y}.
\end{cases}
long long Dist(Point &p, Point &q)
{
int dx = p.x - q.x,
dy = p.y - q.y;
return (long long)dx * dx +
(long long)dy * dy;
}
De asemenea, vom implementa și o funcție TryPoint(x, y) care verifică dacă perechea \((x, y)\) are proprietățile menționate anterior.
void TryPoint(int x, int y)
{
if((x + G.x) % 3 == 0 && (y + G.y) % 3 == 0)
{
P = Point((x + G.x) / 3, (y + G.y) / 3);
if(Dist(P, A) == PA2 && Dist(P, B) == PB2 && Dist(P, C) == PC2)
{
cout << P << '\n';
exit(0);
}
}
}
Vom itera cu x de la \(0\) la \([\sqrt{k}]\) și vom verifica dacă \(k – x^2\) este pătrat perfect. De menționat că va trebui să probăm același lucru și pentru perechile \((-x, -y)\), \((-x, y)\), \((x, -y)\), motiv pentru care vom declara doi vectori dx și dy (având similar cu vectorii de deplasare). La pasul \(0 \leqslant i < 4\), vom valida perechea \(x \cdot \text{dx}[i], y \cdot \text{dy}[i]\).
#include <iostream>
#include <cstdlib>
#include <cmath>
using namespace std;
const int dx[] = {1, 1, -1, -1},
dy[] = {1, -1, 1, -1};
struct Point
{
int x, y;
Point(int xx = 0, int yy = 0): x(xx), y(yy) {}
friend istream& operator >> (istream &in, Point &p)
{
in >> p.x >> p.y;
return in;
}
friend ostream& operator << (ostream &out, const Point &p)
{
out << p.x << ' ' << p.y;
return out;
}
};
Point A, B, C, P, G;
int PA2, PB2, PC2;
long long k;
/// Pătratul distanței dintre punctele p și q
long long Dist(Point &p, Point &q)
{
int dx = p.x - q.x,
dy = p.y - q.y;
return (long long)dx * dx +
(long long)dy * dy;
}
/// Verifică dacă perechea (x, y) convine.
/// Dacă sunt verificate toate condițiile, se afișează
/// coordonatele lui P și se termină execuția programului.
void TryPoint(int x, int y)
{
if((x + G.x) % 3 == 0 && (y + G.y) % 3 == 0)
{
P = Point((x + G.x) / 3, (y + G.y) / 3);
if(Dist(P, A) == PA2 && Dist(P, B) == PB2 && Dist(P, C) == PC2)
{
cout << P << '\n';
exit(0);
}
}
}
int main()
{
cin >> A >> B >> C
>> PA2 >> PB2 >> PC2;
k = 3LL * (PA2 + PB2 + PC2) - (Dist(A, B) + Dist(B, C) + Dist(C, A));
G = Point(A.x + B.x + C.x, A.y + B.y + C.y);
for(int x = 0; 1LL * x * x <= k; x++)
{
int y = (int)sqrt(k - 1LL * x * x);
if(1LL * y * y != k - 1LL * x * x)
continue;
for(int i = 0; i < 4; i++)
TryPoint(x * dx[i], y * dy[i]);
}
cout << P;
return 0;
}
Soluția oficială poate fi accesată aici.
## Ce sunt wormholes?
Un wormhole (în română: „gaură de vierme”) este un concept teoretic din fizică ce descrie un tunel prin spațiu-timp care ar putea conecta două puncte foarte îndepărtate din Univers.
Ideea apare din ecuațiile teoriei relativității generale formulate de Albert Einstein. În 1935, el și Nathan Rosen au descris o structură numită „pod Einstein-Rosen”, considerată primul model teoretic de wormhole.
—-
## 🌀 Cum ar arăta un wormhole?




Un wormhole este adesea reprezentat ca:
Dacă Universul ar fi o foaie de hârtie, un wormhole ar fi ca și cum ai îndoi foaia și ai face o gaură direct între două puncte.
—-
## 🔬 Există wormholes în realitate?
Până în prezent:
Unii cercetători cred că la nivel cuantic ar putea exista micro-wormholes extrem de mici, dar nu există dovezi experimentale clare.
—-
## 🚀 Wormholes în filme și cultură
Conceptul a devenit popular în literatura și filmele SF, unde este folosit pentru călătorii interstelare rapide.
Un exemplu celebru este filmul Interstellar, unde un wormhole permite explorarea altor galaxii.
—-
## 🧠 Sunt posibile călătoriile în timp?
Teoretic, unele modele sugerează că wormholes ar putea permite și deplasarea în timp, nu doar în spațiu. Totuși:
Deocamdată, rămân doar o ipoteză fascinantă.
—-
## ✨ Concluzie
Wormholes reprezintă una dintre cele mai interesante idei din fizica teoretică. Deși nu știm dacă există cu adevărat, ele ne ajută să explorăm limitele cunoașterii despre Univers, spațiu și timp.
Poate într-o zi, ceea ce azi pare science-fiction va deveni realitate. 🌠