This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include <bits/stdc++.h>
using namespace std;
// Zauwazmy, ze INF musi byc wiekszy od MAX_WARTOSC + log(n)
const int INF = 2e9 + 5;
const int MOD = 1e9 + 7;
const int BASE = 1 << 18;
struct Przedzial
{
int L, R;
bool operator < (const Przedzial& inny) const
{
if(L != inny.L)
{
return L < inny.L;
}
else
{
return R < inny.R;
}
}
bool operator == (const Przedzial& inny) const
{
return (L == inny.L && R == inny.R);
}
};
struct Macierz
{
// macierz[x][y] = macierz[najbardziej na prawo bit, ktorego nie musimy zmieniac][najbardziej na lewo bit, ktorego nie musimy zmieniac]
int macierz[2][2];
Macierz()
{
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
macierz[i][j] = 0;
}
}
}
int* operator [] (int indeks)
{
return macierz[indeks];
}
const int* operator [] (int indeks) const
{
return macierz[indeks];
}
Macierz operator * (const Macierz& inny) const
{
Macierz wynik;
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
for(int k = 0; k < 2; k++)
{
wynik[i][k] = (wynik[i][k] + 1LL * macierz[i][j] * inny.macierz[j][k]) % MOD;
}
}
}
return wynik;
}
};
struct Wierzcholek
{
bool czy_istnieje = false;
int najbardziej_na_lewo, najbardziej_na_prawo;
Macierz macierz;
void init(Przedzial przedzial)
{
najbardziej_na_lewo = przedzial.L, najbardziej_na_prawo = przedzial.R;
int rozmiar = (najbardziej_na_prawo - najbardziej_na_lewo) / 2 + 1;
macierz[0][0] = 1;
macierz[0][1] = 0;
macierz[1][0] = rozmiar - 1;
macierz[1][1] = 1;
}
void combine(const Wierzcholek& a, const Wierzcholek& b)
{
czy_istnieje = a.czy_istnieje || b.czy_istnieje;
if(!a.czy_istnieje)
{
*this = b;
return;
}
if(!b.czy_istnieje)
{
*this = a;
return;
}
najbardziej_na_lewo = a.najbardziej_na_lewo;
najbardziej_na_prawo = b.najbardziej_na_prawo;
const int odleglosc = b.najbardziej_na_lewo - a.najbardziej_na_prawo;
Macierz mid;
if(odleglosc % 2 == 0)
{
mid[0][0] = 1;
mid[1][0] = 1;
}
mid[0][1] = max(0, (odleglosc - 1) / 2);
mid[1][1] = max(0, (odleglosc - 1) / 2);
mid[1][1] = (mid[1][1] + 1) % MOD;
macierz = (b.macierz * mid) * a.macierz;
}
};
vector <Wierzcholek> segtree(BASE << 1);
set <Przedzial> przedzialy;
vector <vector <Przedzial>> wydarzenia;
int timer;
void update(int v)
{
v += BASE;
segtree[v].czy_istnieje = !segtree[v].czy_istnieje;
// dzielimy v przez 2
v >>= 1;
while(v)
{
// mnozymy razy 2
int lewy_syn = v << 1;
// mnozymy razy 2 i dodajemy 1
int prawy_syn = (v << 1) + 1;
segtree[v].combine(segtree[lewy_syn], segtree[prawy_syn]);
// dzielimy v przez 2
v >>= 1;
}
}
Wierzcholek query(Wierzcholek& start)
{
Wierzcholek wynik;
wynik.combine(start, segtree[1]);
return wynik;
}
void dodaj_jesli_niepuste(int L, int R)
{
if(L <= R)
{
wydarzenia[timer].push_back({L, R});
przedzialy.insert({L, R});
}
}
void usun(set <Przedzial>::iterator it)
{
wydarzenia[timer].push_back({it->L, it->R});
przedzialy.erase(it);
}
void dodaj_na_zewnatrz(const int liczba)
{
auto R = przedzialy.upper_bound({liczba, INF});
if(liczba + 1 == R->L)
{
// tuz przed przedzialem R
// caly przedzial kompresowujemy do R->R + 1
const int nowa_wartosc = R->R + 1;
usun(R);
dodaj_na_zewnatrz(nowa_wartosc);
return;
}
auto L = prev(R);
if(L->R + 1 == liczba)
{
// tuz za przedzialem L
// usuwamy ostatni element przedzialu L
dodaj_jesli_niepuste(L->L, L->R - 2);
usun(L);
dodaj_na_zewnatrz(liczba + 1);
return;
}
Przedzial nowy_przedzial = {liczba, liczba};
if(liczba + 2 == R->L)
{
nowy_przedzial.R = R->R;
usun(R);
}
if(L->R + 2 == liczba)
{
nowy_przedzial.L = L->L;
usun(L);
}
dodaj_jesli_niepuste(nowy_przedzial.L, nowy_przedzial.R);
}
void dodaj_mozliwe_do_wewnatrz(const int liczba)
{
auto it = przedzialy.upper_bound({liczba, INF});
it--;
if(!(it->L <= liczba && liczba <= it->R))
{
dodaj_na_zewnatrz(liczba);
return;
}
// Teraz juz wiemy, ze liczba jest w przedziale
if(it->L % 2 != liczba % 2)
{
// Mamy przypadek dodania do 0 w ciagu ...01010...
// ...001010101010100...
// + 1
// = ...001010100000010...
dodaj_jesli_niepuste(it->L, liczba - 1);
const int nowa_wartosc = it->R + 1;
usun(it);
dodaj_na_zewnatrz(nowa_wartosc);
return;
}
// Mamy przypadek dodania do 1 w ciagu ...01010...
// ...001010101010100...
// + 1
// = ...100101011010100...
// = ...100101000000010...
const vector <int> nowe_wartosci = {it->L - 2, it->R + 1};
dodaj_jesli_niepuste(it->L + 1, liczba - 1);
usun(it);
for(auto a : nowe_wartosci)
{
if(a == -2)
{
// Fibonacci[-2] = 0
continue;
}
if(a == -1)
{
// Fibonacci[-1] = Fibonacci[0]
a = 0;
}
dodaj_na_zewnatrz(a);
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
wydarzenia.resize(n);
// Dla latwiejszej implementacji dodajemy dwa przedzialy
przedzialy.insert({-INF, -INF});
przedzialy.insert({INF, INF});
for(timer = 0; timer < n; timer++)
{
int liczba;
cin >> liczba;
liczba--;
dodaj_mozliwe_do_wewnatrz(liczba);
}
vector <Przedzial> wszystkie;
for(auto& wydarzenie : wydarzenia)
{
for(auto& x : wydarzenie)
{
wszystkie.push_back(x);
}
}
sort(wszystkie.begin(), wszystkie.end());
wszystkie.resize(unique(wszystkie.begin(), wszystkie.end()) - wszystkie.begin());
for(int i = 0; i < (int) wszystkie.size(); i++)
{
segtree[BASE + i].init(wszystkie[i]);
}
Wierzcholek start;
start.init({-1, -1});
start.czy_istnieje = true;
for(timer = 0; timer < n; timer++)
{
for(auto& x : wydarzenia[timer])
{
int v = lower_bound(wszystkie.begin(),wszystkie.end(), x) - wszystkie.begin();
update(v);
}
Wierzcholek wynik = query(start);
cout << wynik.macierz[1][1] << "\n";
}
return 0;
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |