Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/4: Рейтинг темы: голосов - 4, средняя оценка - 5.00
0 / 0 / 0
Регистрация: 20.03.2022
Сообщений: 12

Система уравнений

19.04.2023, 19:22. Показов 901. Ответов 12

Студворк — интернет-сервис помощи студентам
Решал я на вид просую задачку, условие простое: пользователь вводит 2 числа P(1<=P<=109), Q(1<=Q<=1018), имеется система уравнений x+y+z=P и x*y*z=Q, нужно найти минимальный x,y,z, если таких нет вывести -1. Загвостка заключается в том, что в 14 из 18 тестов числа больше миллиарада и тут уже давит time limit... Вот пример моего кода
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
using namespace std;
 
int main(){
    setlocale(LC_ALL, "Russian");
    int P, Q;
    cin>>P>>Q;
    int *del = new int;
    int n = 0;
    for(int i = 1; i<Q; i++){  //находим делители числа
        if(Q%i == 0){
            del[n] = i;
            n++;
        }
    }
    n++;
    int Y = 1;
    for(int i = 0; i<n and Y == 1; i++){
        for(int j = 0; j<n and Y == 1; j++){
            for(int k = 0; k<n and Y == 1; k++){
                int x = del[i];
                int y = del[j];
                int z = del[k];
                if(x+y+z == P and x*y*z == Q){
                    cout<<x<<" "<<y<<" "<<z<<endl;
                    Y=0;
                }
            }
        }
    }
    if(Y == 1)
        cout<<-1;
}
и вот еще пару тестиков(input:output)
7 8: 1 2 4
26 288: 2 12 12
1942743 221897492810000821: 352897 739117 850729
10440084 479525667212164032:58286 864432 9517366
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
19.04.2023, 19:22
Ответы с готовыми решениями:

Система уравнений
Помогите розвязать систему уравнений

Система уравнений
Решить систему уравнений с помощью с++

Система уравнений
Всем привет. Не очень разбираюсь в системах, кое что нарешал, но получается херня, не бейте меня ногами только, прошу помощи :-| #include...

12
Модератор
Эксперт С++
 Аватар для zss
13769 / 10962 / 6491
Регистрация: 18.12.2011
Сообщений: 29,238
19.04.2023, 19:36
Цитата Сообщение от C0nstanta Посмотреть сообщение
int *del = new int;
Как это вообще может работать?
память выделена под ОДНО число, т.е. есть только элемент del[0].

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
using namespace std;
 
int main(){
    setlocale(LC_ALL, "Russian");
    long long P, Q;
    cin>>P>>Q;
    cin.get();
    int n = 0;
    for(long long i = 1; i*i<Q; i++)
    {  //находим к-во делителей числа
        if(Q%i == 0)
            n++;
    }
    long long* del=new long long[n+1];
    n=0;
    for(long long i = 1; i*i<Q; i++)
    {  //находим делители числа
        if(Q%i == 0)
            del[n++]=i;
    }
    del[n++]=Q;
    bool Y = true;
    for(int i = 0; i<n && Y ; i++){
        long long x = del[i];
        for(int j = i; j<n && Y; j++){ //  !!   j=i
            long long y = del[j];
            for(int k = j; k<n && Y; k++){ // !!!  k=j
                long long z = del[k];
                if(x+y+z == P && x*y*z == Q){
                    cout<<x<<" "<<y<<" "<<z<<endl;
                    Y=false;
                }
            }
        }
    }
    if(Y)
        cout<<"-1";
    delete[] del;
    cin.get();
    return 0;
}
На моём компьютере релиз W32 последний вариант
10440084 479525667212164032:58286 864432 9517366
считает порядка 30 секунд.
1
place status here
 Аватар для gunslinger
3186 / 2220 / 640
Регистрация: 20.07.2013
Сообщений: 6,008
19.04.2023, 22:04
А если использовать не тройной цикл, а двойной?
Ниже сырой набросок без приведенных выше оптимизаций. Но идея должна быть понятна.

Вспомогательные функции:
C++
1
2
3
4
5
6
7
8
9
unsigned long long func_x (unsigned long long y, unsigned long long z, unsigned long long P)
{
  return P - y - z;
}
//---------------------------------------------------------------------------
unsigned long long func_Q (unsigned long long y, unsigned long long z, unsigned long long P)
{
  return func_x(y, z, P) * y * z;
}
Основной код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
  unsigned long long i, j, x, y, z, P = 7, Q = 8;
  int status = -1;
  for (j = 1; j <= Q; j++)
    for (i = j; i <= Q / j; i++)
      if (func_Q(i, j, P) == Q)
      {
        y = i, z = j, x = func_x(y, z, P);
        i = Q + 1, j = Q + 1;
        status = 1;
      }
 
  // выводим результат
  String result = (status == 1) ? String(x) + "  " + String(y) + "  " + String(z) : String("-1");
0
0 / 0 / 0
Регистрация: 20.03.2022
Сообщений: 12
20.04.2023, 12:57  [ТС]
gunslinger, не много не пойму что не так с динамическим массивом. Но к сожалению ваше решение мне не очень подходит из-за времени, там ограничение около 2 секунд вроде

Добавлено через 6 минут
немного не пойму. Mожете выслать полный код?
0
Модератор
Эксперт С++
 Аватар для zss
13769 / 10962 / 6491
Регистрация: 18.12.2011
Сообщений: 29,238
20.04.2023, 12:57
Цитата Сообщение от C0nstanta Посмотреть сообщение
что не так с динамическим массивом
Память выделять нужно так, чтобы все элементы поместились, а не только один.

Кстати, действительно, 3-й цикл лишний, т.к. z=Q/(xy) (или z=P-x-y)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
using namespace std;
 
int main(){
    setlocale(LC_ALL, "Russian");
    long long P, Q,x,y,z;
    cin>>P>>Q;
    cin.get();
    int n = 0;
    for(long long i = 1; i*i<Q; i++)
    {  
        if(Q%i == 0)
            n++;
    }
    long long* del=new long long[n+1];
    n=0;
    for(long long i = 1; i*i<Q; i++)
    {  
        if(Q%i == 0)
            del[n++]=i;
    }
    del[n++]=Q;
    bool NotFound = true;
    for(int i = 0; i<n && NotFound ; i++)
    {
        x = del[i];
        for(int j = i; j<n; j++)
        {
            y = del[j];
            z = Q/(x*y);
            if(x*y*z == Q && x+y+z == P)
            {
                NotFound=false;break;
            }
        }
    }
    if(NotFound)
        cout<<"-1";
    else
        cout<<x<<" "<<y<<" "<<z<<endl;
    delete[] del;
    cin.get();
    return 0;
}
Время уменьшается раза в два.
2
0 / 0 / 0
Регистрация: 20.03.2022
Сообщений: 12
20.04.2023, 13:43  [ТС]
zss, в общем... я не знаю что не так, но теперь же ваш код выводит нужный ответ за 0,09 секунд и проходит 7 тестов, но все же по остальным таймаут, я попробовал удалить последний цикл заменив его на z=P-x-y, но все же еще нужно оптимизировать
0
фрилансер
 Аватар для Алексей1153
6444 / 5637 / 1128
Регистрация: 11.10.2019
Сообщений: 14,997
20.04.2023, 14:18
Цитата Сообщение от zss Посмотреть сообщение
for(long long i = 1; i*i<Q; i++)
    {  
        if(Q%i == 0)
            n++;
    }
можно i*i<Q заменить на сравнение i с заранее посчитанным корнем из Q

Цитата Сообщение от zss Посмотреть сообщение
for(long long i = 1; i*i<Q; i++)
    {  
        if(Q%i == 0)
            del[n++]=i;
    }
тут то же самое

а также
Цитата Сообщение от zss Посмотреть сообщение
if(Q%i == 0)
            n++;
- тут избавиться от if

Добавлено через 10 минут
итог (нужно протестировать):

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <cmath>
using namespace std;
 
int main(){
    setlocale(LC_ALL, "Russian");
    long long P, Q,x,y,z;
    cin>>P>>Q;
    cin.get();
    int n = 0;
    
    const double sqrtQ=std::sqrt(Q);
    for(long long i = 1; i<sqrtQ; i++)
    {  
        //if(Q%i == 0)n++;
        n+=!(Q%i);
    }
    long long* del=new long long[n+1];
    n=0;
    for(long long i = 1; i<sqrtQ; i++)
    {  
        if(Q%i == 0)
            del[n++]=i;
    }
    del[n++]=Q;
    bool NotFound = true;
    for(int i = 0; i<n && NotFound ; i++)
    {
        x = del[i];
        for(int j = i; j<n; j++)
        {
            y = del[j];
            z = Q/(x*y);
            if(x*y*z == Q && x+y+z == P)
            {
                NotFound=false;break;
            }
        }
    }
    if(NotFound)
        cout<<"-1";
    else
        cout<<x<<" "<<y<<" "<<z<<endl;
    delete[] del;
    cin.get();
    return 0;
}
1
Модератор
Эксперт С++
 Аватар для zss
13769 / 10962 / 6491
Регистрация: 18.12.2011
Сообщений: 29,238
20.04.2023, 14:20
Движемся дальше.
Если задано x, то для нахождения y и z достаточно решить систему из 2 уравнений
z+y=P-x
z*y=Q/x
В результате, избавляемся от второго цикла
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <math.h>
using namespace std;
typedef unsigned long long LL;
int main(){
    setlocale(LC_ALL, "Russian");
    LL P, Q,x,y,z;
    cin>>P>>Q;
    cin.get();
    int n = 0;
    for(LL i = 1; i*i<Q; i++)
    {  
        if(Q%i == 0)
            n++;
    }
    LL* del=new LL[n+1];
    n=0;
    for(LL i = 1; i*i<Q; i++)
    {  
        if(Q%i == 0)
            del[n++]=i;
    }
    del[n++]=Q;
    bool NotFound = true;
    for(int i = 0; i < n; i++)
    {
        x = del[i];
        LL P2=P-x;
        LL Q2=Q/x;
        y=P2/2-(LL)sqrt(P2*P2/4.-Q2);
        z=P2-y;
        if(x*y*z == Q)
        {
            NotFound=false;
            break;
        }
    }
    if(NotFound)
        cout<<"-1";
    else
        cout<<x<<" "<<y<<" "<<z<<endl;
    delete[] del;
    cin.get();
    return 0;
}
неприятным моментом здесь будет sqrt(P2*P2/4.-Q2)
т.к. он выполняется в плавающей арифметике.
Надо как-то избавиться от него.
1
Объявлятель переменных
 Аватар для SpBerkut
1225 / 411 / 321
Регистрация: 24.09.2011
Сообщений: 1,279
20.04.2023, 14:59
Лучший ответ Сообщение было отмечено C0nstanta как решение

Решение

Попробуйте. А вдруг.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <cmath>
 
long long gcd(long long a, long long b){
    if(b==0) return a;
    return gcd(b, a%b);
}
 
long long secret(const long long P, const long long Q, long long x) {
    long long f = P*P*x - 2*P*x*x + x*x*x - 4*Q;
    long long g = gcd(f, x);
    f /= g;
    x /= g;
    if (g > 1)
        return (sqrt(x * f)) / (2*x);
    else
        return (sqrt(f) * sqrt(x) / (2*x*g));
}
 
int main()
{
    long long P;
    long long Q;
    std::cin >> P >> Q;
    bool find = false;
    for (long long x = 1; x < pow(Q, 1.0/3); x++) {
        if (Q % x) continue;
        long long s = (P - x)/2;
        long long sc = secret(P, Q, x);
        if ( Q / x == s*s - sc*sc ) {
            std::cout << x << '\t' << s - secret(P, Q, x) << '\t' << s + secret(P, Q, x);
            find = true;
            break;
        }
    }
    if (!find) std::cout << -1;
}
Добавлено через 35 минут
На всякого мудреца довольно простоты.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <cmath>
 
int main()
{
    long long P, Q, x, y, z, Px, Qx, d;
    std::cin >> P >> Q;
    bool find = false;
    for (x = 1; x < pow(Q, 1.0/3); x++) {
        if (Q % x) continue;
        Px = P - x;
        Qx = Q / x;
        d = Px*Px - 4*Qx;
        y = (Px - sqrt(d))/2;
        z = (Px + sqrt(d))/2;
        if ( (Q == x*y*z) && (x+y+z == P) ) {
            std::cout << x << '\t' << y << '\t' << z;
            find = true;
            break;
        }
    }
    if (!find) std::cout << -1;
}
2
0 / 0 / 0
Регистрация: 20.03.2022
Сообщений: 12
20.04.2023, 16:40  [ТС]
Я фигею... Ведь точно знал что есть математическое решение. Можете пожалуйста +- объяснить принцип (я про второй код), код не проходит лишь один тест(input: output)
3000000 1000000000000000000:1000000 1000000 1000000
0
Объявлятель переменных
 Аватар для SpBerkut
1225 / 411 / 321
Регистрация: 24.09.2011
Сообщений: 1,279
20.04.2023, 16:48
Цитата Сообщение от C0nstanta Посмотреть сообщение
код не проходит лишь один тест
А так?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <iostream>
#include <cmath>
 
struct pair {
    long long value = 0;
    unsigned power = 0;
}; 
 
int main()
{
    long long P, Q, x, y, z, Px, Qx, d;
    pair factors[60];
    unsigned magic[60] = {};
    std::cin >> P >> Q;
    unsigned count = 1-Q%2;
    long long N = Q;
    bool factorFound = false;
    while (N % 2 == 0) {
        if (!factorFound) {
            factorFound = true;
            factors[count-1].value = 2;
        }
        factors[count - 1].power++;
        N /= 2;
    }
    for (long long x = 3; x <= N; x+=2) {
        if (N % x) continue;
        count++;
        factorFound = false;
        while (N % x == 0) {
            if (!factorFound) {
                factorFound = true;
                factors[count-1].value = x;
            }
            factors[count - 1].power++;
            N /= x;
        }
    }
    
    magic[0] = 1;
    for (unsigned i = 1;  i < count; i++) {
        magic[i] = magic[i-1]*(factors[i-1].power+1);
    }
    
    unsigned t = 1;
    
    for (unsigned i = 0;  i < count; i++) {
        t *= factors[i].power+1;
    }
 
    bool find = false;
    for (unsigned i = 1; i <= t; i++) {
        x = 1;
        unsigned j = i;
        for (int k = count-1; k >= 0; k--) {
            x *= pow(factors[k].value, j / magic[k]);
            j %= magic[k];
        }
        
        Px = P - x;
        Qx = Q / x;
        d = Px*Px - 4*Qx;
        y = (Px - sqrt(d))/2;
        z = (Px + sqrt(d))/2;
        if ( (Q == x*y*z) && (x+y+z == P) ) {
            std::cout << x << '\t' << y << '\t' << z;
            find = true;
            break;
        }
    }
    if (!find) std::cout << -1;
}
1
0 / 0 / 0
Регистрация: 20.03.2022
Сообщений: 12
20.04.2023, 17:43  [ТС]
хах... так только все крашнулось, впринципе не так важно, код то рабочий
0
Объявлятель переменных
 Аватар для SpBerkut
1225 / 411 / 321
Регистрация: 24.09.2011
Сообщений: 1,279
21.04.2023, 09:52
Цитата Сообщение от C0nstanta Посмотреть сообщение
Можете пожалуйста +- объяснить принцип (я про второй код)
Принцип следующий. Т.к. x*y*z = Q, значит min(x, y, z) не может превосходить значения в Q^(1/3).
Предположим, что x = min(x, y, z). Теперь переберём все возможные его значения от 1 до Q^(1/3). Т.к. Q <= 10^18, максимум придётся перебрать всего 1000000 значений.
Для конкретного x мы можем провернуть следующий фокус.

y*z = Q/x;
y+z = P-x;

Решим эту систему относительно переменных y и z. Для упрощения записи Qx = Q/x, Px = P - x;

z = Px - y;
y = Qx/z = Qx / (Px - y);

y * (Px - y) = Qx;
y*y - Px*y + Qx = 0;

Получили квадратное уравнение.

D = Px*Px - 4*Qx;

y = (-(-Px) - sqrt(D))/2.
z = (-(-Px) + sqrt(D))/2.

Проверяем полученные значения на корректность и если сошлось, то выводим результат.

В моём последнем решении я не стал перебирать все значения x подряд. Сначала Q раскладываем на простые множители с их степенью.

Например число 479525667212164032 = 2^6 * 3^4 * 19 * 23 * 29 * 151 * 193 * 211 * 1187. Далее я перебираю все возможные наборы множителей. Общее количество вариантов определяется просто — к показателям степеней прибавляется единица и все числа перемножаются. Для числа, рассмотренного выше количество вариантов составит 4480. В 170 раз меньше, чем перебирать все варианты в лоб. Можно чуть улучшить и отсеивать наборы, произведение которых превышает Q^(1/3). Но и без этого получилось неплохо.
Цитата Сообщение от C0nstanta Посмотреть сообщение
так только все крашнулось, впринципе не так важно
Требую подробностей.
3
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
21.04.2023, 09:52
Помогаю со студенческими работами здесь

Система уравнений
#include &lt;iostream&gt; using namespace std; int main() { int n, i, j, k; double d, s; cout &lt;&lt; &quot;sin(9x) + cos(7y) - 5z*z =...

Система уравнений
Здравствуйте, как на с++ решить систему уравнения такого характера U1 + V1 = 3 U1 + V2 = 2 U1 + V4 = 1 U2 + V1 = 2 U2 + V3 = 1 ...

Система уравнений
Помогите решить. $$y=\begin{cases}({2}^{3 \times x - 1}) \times ({x}^{2}),&amp; \text{$|x| \geq 5$;}\\{\ln |x|}^{-1},&amp; \text{$0 \le...

система уравнений
система уравнений...

Система уравнений
B*(x - x0) + C*(y - y0) = 0 y = k*x + b Нужно узнать координаты x и y Помогите вывести


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Новые блоги и статьи
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка. Рецензия / Мнение/ Перевод https:/ / **********/ gallery/ thinkpad-x220-tablet-porn-gzoEAjs . . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru