• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Zadane The BOSS Can Count Pairs Codeforces

Aruba Cloud VPS - 50% taniej przez 3 miesiące!
0 głosów
216 wizyt
pytanie zadane 6 czerwca 2023 w Algorytmy przez pasjonat_algorytmiki Pasjonat (19,540 p.)
Mam problem z takim zadaniem: https://codeforces.com/problemset/problem/1830/B

Nie wiem jak zrobić szybciej niż O(N^2). Zastanawiałem się nad sqrt, ale nic nie wymyśliłem. Bardzo byłbym wdzięczny za hinta.

Z góry dzięki!

1 odpowiedź

+2 głosów
odpowiedź 6 czerwca 2023 przez Whistleroosh Maniak (57,360 p.)
wybrane 7 czerwca 2023 przez pasjonat_algorytmiki
 
Najlepsza
Kluczową obserwacją jest ograniczenie na min(a_i, a_j) dla dowolnej pary (i, j).
komentarz 7 czerwca 2023 przez pasjonat_algorytmiki Pasjonat (19,540 p.)
Wsumie mogą tu wchodzić sumy harmoniczne.
komentarz 7 czerwca 2023 przez Whistleroosh Maniak (57,360 p.)
Niestety nie, a przynajmniej nie wiem jak nimi to rozwiązać
komentarz 7 czerwca 2023 przez pasjonat_algorytmiki Pasjonat (19,540 p.)
Wiemy, że min(A[i], A[j]) <= sqrt, czyli teoretycznie możemy dla każdej z sqrt wartości sprawdzać N liczb.
komentarz 7 czerwca 2023 przez Whistleroosh Maniak (57,360 p.)
Dobry pomysł
komentarz 7 czerwca 2023 przez pasjonat_algorytmiki Pasjonat (19,540 p.)

Mam coś takiego:

#include <iostream>
#include <vector>
#include <algorithm>
#include <map>

using namespace std;
typedef long long ll;

ll q = 0, n = 0, k = 450, ile_rownych = 0;
ll wyn = 0;
vector<ll> A;
vector<ll> B;
vector<vector<ll>> wystapienia;
vector<ll> ile_mamy;
vector<ll> idx_poprzedniej;

int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);


    cin >> q;
    while(q--)
    {
        cin >> n;
        A.assign(n,-1);
        for (int i = 0; i < n; ++i)
            cin >> A[i];
        B.assign(n,-1);
        for (int i = 0; i < n; ++i)
            cin >> B[i];

        wystapienia.assign(n+1,{});
        for (int i = 0; i < n; ++i)
            wystapienia[A[i]].push_back(B[i]);

        ile_mamy.assign(n+1,0);
        idx_poprzedniej.assign(n+1,-1);

        wyn = 0;
        for (int i = 1; i <= min(n,k); ++i)
        {
            for (int j = 0; j < wystapienia[i].size(); ++j)
            {
                int val = wystapienia[i][j];
                if (idx_poprzedniej[val] != i)
                {
                    idx_poprzedniej[val] = i;
                    ile_mamy[val] = 1;
                }
                else
                    ile_mamy[val]++;
            }
            for (int j = 0; j < n; ++j)
            {
                if (A[j] <= i)
                    continue;
                ll iloczyn = i * A[j], ile_zostalo = iloczyn - B[j];
                if (ile_zostalo <= 0 or ile_zostalo > n)
                    continue;
                if (idx_poprzedniej[ile_zostalo] == i)
                {
                    wyn += ile_mamy[ile_zostalo];
                }
            }
        }

        ll do_dodania = 0;
        for (int i = 1; i <= n and i * i <= 2*n+1; ++i)
        {
            if (wystapienia[i].size() <= 1)
                continue;
            map<int,int> stat;
            for (int j = 0; j < wystapienia[i].size(); ++j)
            {
                int val = wystapienia[i][j];
                if (auto it = stat.find(val) != stat.end())
                    stat[val]++;
                else
                    stat[val] = 1;
            }
            for (int j = 0; j < wystapienia[i].size(); ++j)
            {
                int val = wystapienia[i][j], ile_brakuje = i*i - val;
                if (auto it = stat.find(ile_brakuje) != stat.end())
                {
                    if (ile_brakuje == val)
                        do_dodania += stat[ile_brakuje]-1;
                    else
                        do_dodania += stat[ile_brakuje];
                }
            }
        }
        wyn += do_dodania / 2;
        cout << wyn << '\n';
    }

    return 0;
}

Ogołnie działa dobrze, ale na max tescie daje lekko za małe odpowiedzi. Chyba już 1,5h to debuguje i nwm co nie dziala.

komentarz 7 czerwca 2023 przez pasjonat_algorytmiki Pasjonat (19,540 p.)
tak czytam ten kod i nie widzę błędu. Muszę napisać sprawdzarkę.
komentarz 7 czerwca 2023 przez pasjonat_algorytmiki Pasjonat (19,540 p.)

Napisałem sprawdzarkę, z brutem O(N^2), i na testach N = 1000 daje poprawne odpowiedzi na wszystkich, bardzo dużo testach

#include <iostream>
#include <vector>
#include <algorithm>
#include <map>

using namespace std;
typedef long long ll;

ll q = 0, n = 0, k = 450;
ll wyn = 0;
vector<ll> A;
vector<ll> B;
vector<vector<ll>> wystapienia;
vector<ll> ile_mamy;
vector<ll> idx_poprzedniej;

ll N = 0;
vector<ll> gen_A, gen_B;

inline int rnd(int l, int p)
{
    return rand() % (p-l+1) + l;
}

inline void generuj()
{
    srand(time(0));
    N = rnd(1,1000);
    gen_A.assign(N,-1);
    for (int i = 0; i < N; ++i)
        gen_A[i] = rnd(1,N);
    gen_B.assign(N,-1);
    for (int i = 0; i < N; ++i)
        gen_B[i] = rnd(1,N);
}

inline void wypisuj()
{
    cout << N << '\n';
    for (int i = 0; i < N; ++i)
        cout << gen_A[i] << " ";
    cout << '\n';
    for (int i = 0; i < N; ++i)
        cout << gen_B[i] << ' ';
    cout << '\n' << '\n';
}

inline ll brut()
{
    ll res = 0;
    n = N;
    A = gen_A, B = gen_B;
    for (int i = 0; i < n; ++i)
        for (int j = i+1; j < n; ++j)
            if (A[i] * A[j] == B[i] + B[j])
                res++;
    return res;
}

inline ll wzo()
{
    n = N, A = gen_A, B = gen_B;
    wystapienia.assign(n+1,{});
    for (int i = 0; i < n; ++i)
        wystapienia[A[i]].push_back(B[i]);

    ile_mamy.assign(n+1,0);
    idx_poprzedniej.assign(n+1,-1);

    wyn = 0;
    for (int i = 1; i <= min(n,k); ++i)
    {
        for (int j = 0; j < wystapienia[i].size(); ++j)
        {
            int val = wystapienia[i][j];
            if (idx_poprzedniej[val] != i)
            {
                idx_poprzedniej[val] = i;
                ile_mamy[val] = 1;
            }
            else
                ile_mamy[val]++;
           }
        for (int j = 0; j < n; ++j)
        {
            if (A[j] <= i)
                continue;
            ll iloczyn = i * A[j], ile_zostalo = iloczyn - B[j];
            if (ile_zostalo <= 0 or ile_zostalo > n)
                continue;
            if (idx_poprzedniej[ile_zostalo] == i)
            {
                wyn += ile_mamy[ile_zostalo];
            }
        }
    }

    ll do_dodania = 0;
    for (int i = 1; i <= n and i * i <= 2*n; ++i)
    {
        if (wystapienia[i].size() <= 1)
            continue;
        map<int,int> stat;
        for (int j = 0; j < wystapienia[i].size(); ++j)
        {
            int val = wystapienia[i][j];
            if (auto it = stat.find(val) != stat.end())
                stat[val]++;
            else
                stat[val] = 1;
        }
        for (int j = 0; j < wystapienia[i].size(); ++j)
        {
            int val = wystapienia[i][j], ile_brakuje = i*i - val;
            if (auto it = stat.find(ile_brakuje) != stat.end())
            {
                if (ile_brakuje == val)
                    do_dodania += stat[ile_brakuje]-1;
                else
                    do_dodania += stat[ile_brakuje];
            }
        }
    }
    wyn += do_dodania / 2;
    return wyn;
}

inline void testuj()
{
    while(true)
    {
        generuj();
        //cout << wzo() << " " << wzo() << " " << brut() << " " << brut() << endl;
        if (wzo() != brut())
            break;
        cout << "t" << '\n';
    }
    wypisuj();
}

int main()
{
    //ios_base::sync_with_stdio(0);
    //cin.tie(0);
    //cout.tie(0);

    testuj();

    return 0;
}

bardzo dziwne

komentarz 7 czerwca 2023 przez Whistleroosh Maniak (57,360 p.)
Pierwiastek jest za mały. Powinno być sqrt(4*1e5)
1
komentarz 7 czerwca 2023 przez pasjonat_algorytmiki Pasjonat (19,540 p.)
no i jest ac, dzięki za pomoc!

Podobne pytania

0 głosów
0 odpowiedzi 232 wizyt
0 głosów
1 odpowiedź 472 wizyt
0 głosów
0 odpowiedzi 221 wizyt
pytanie zadane 10 marca w Algorytmy przez Dani Obywatel (1,450 p.)

93,164 zapytań

142,176 odpowiedzi

321,928 komentarzy

62,491 pasjonatów

Advent of Code 2024

Top 15 użytkowników

  1. 682p. - dia-Chann
  2. 670p. - CC PL
  3. 669p. - Łukasz Piwowar
  4. 656p. - Łukasz Eckert
  5. 643p. - Michal Drewniak
  6. 567p. - ssynowiec
  7. 526p. - rucin93
  8. 453p. - Marcin Putra
  9. 428p. - rafalszastok
  10. 423p. - Adrian Wieprzkowicz
  11. 422p. - zmmz89
  12. 415p. - Mikbac
  13. 410p. - Piotr Aleksandrowicz
  14. 408p. - ksalekk
  15. 402p. - Mariusz Fornal
Szczegóły i pełne wyniki

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Wprowadzenie do ITsec, tom 1 Wprowadzenie do ITsec, tom 2

Można już zamawiać dwa tomy książek o ITsec pt. "Wprowadzenie do bezpieczeństwa IT" - mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy aż 15% zniżki! Dziękujemy ekipie Sekuraka za fajny rabat dla naszej Społeczności!

...